From 84b5e4e9386eebba18571b57ff1ee9a027609a75 Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Sat, 6 Jul 2024 16:20:29 +0200 Subject: [PATCH 01/43] Update CHANGELOG with v3.5.2 details --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fef2871bc..16c1f92bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ ## 3.5.2 * Generate BIOS JSON's file during start-up and after BIOS update +* Internal: + * make starting DCSpy client in thread more flexible ## 3.5.1 * Add missing `F-4E-45MC.yaml` - #316 (@emcek) From dc6000e8cc162fad09b578254fd21202ba119311 Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Sun, 14 Jul 2024 22:15:53 +0200 Subject: [PATCH 02/43] Add Qt signal handling to utils module as SignalHandler --- dcspy/utils.py | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/dcspy/utils.py b/dcspy/utils.py index 945806bfd..36c5bff30 100644 --- a/dcspy/utils.py +++ b/dcspy/utils.py @@ -425,6 +425,70 @@ def get_sha_for_current_git_ref(git_ref: str, repo: str = 'DCS-Skunkworks/dcs-bi return head_commit.hexsha +class WorkerSignals(QObject): + """ + Defines the signals available from a running worker thread. + + Supported signals are: + * finished - no data + * error - tuple with exctype, value, traceback.format_exc() + * result - object/any type - data returned from processing + * progress - int as indication of progress + * stage - string with current stage + * count - tuple of int as count of events + """ + + finished = Signal() + error = Signal(tuple) + result = Signal(object) + progress = Signal(int) + stage = Signal(str) + count = Signal(tuple) + + +class SignalHandler: + """Qt signal handler for GUI notification""" + def __init__(self, signals_dict: dict[str, Callable], signals: QObject = WorkerSignals()) -> None: + """ + Used for passing signals function and emit to Qt GUI. + + :param signals_dict: The keys are the signal names, and the values are the corresponding handler functions. + :param signals: QObject used for handling signals, the default is WorkerSignals class. + """ + self._sig_handler = signals_dict + self.signals = signals + for signal, handler in signals_dict.items(): + getattr(self.signals, signal).connect(handler) + + def got_signals_for_interface(self) -> bool: + """ + Check if there are progress or count signals for the interface. + + :return: True if there are signals for the interface, False otherwise. + """ + if self._sig_handler.get('progress', False): + return True + if self._sig_handler.get('count', False): + return True + return False + + def emit(self, sig_name: str, **kwargs) -> None: + """ + Emits the signal with the name and value. + + :param sig_name: The name of the signal to emit. + """ + value = kwargs.get('value', 'No value set') + if value == 'No value set': + getattr(self.signals, sig_name).emit() + else: + getattr(self.signals, sig_name).emit(value) + + def __str__(self) -> str: + signals = {signal: handler.__name__ for signal, handler in self._sig_handler.items()} + return f'{signals}' + + class CloneProgress(git.RemoteProgress): """Handler providing an interface to parse progress information emitted by git.""" OP_CODES: ClassVar[list[str]] = ['BEGIN', 'CHECKING_OUT', 'COMPRESSING', 'COUNTING', 'END', 'FINDING_SOURCES', 'RECEIVING', 'RESOLVING', 'WRITING'] From 06b1f99364f61f27bd190656b4c85229c3632f97 Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Sun, 14 Jul 2024 22:16:08 +0200 Subject: [PATCH 03/43] Refactor signal handling in GitProgressHandler --- dcspy/utils.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/dcspy/utils.py b/dcspy/utils.py index 36c5bff30..622a31ad4 100644 --- a/dcspy/utils.py +++ b/dcspy/utils.py @@ -20,6 +20,7 @@ import yaml from packaging import version from psutil import process_iter +from PySide6.QtCore import QObject, Signal from requests import get from dcspy.models import (CTRL_LIST_SEPARATOR, DCS_BIOS_REPO_DIR, ControlDepiction, ControlKeyData, DcsBiosPlaneData, DcspyConfigYaml, Gkey, LcdButton, @@ -494,16 +495,14 @@ class CloneProgress(git.RemoteProgress): OP_CODES: ClassVar[list[str]] = ['BEGIN', 'CHECKING_OUT', 'COMPRESSING', 'COUNTING', 'END', 'FINDING_SOURCES', 'RECEIVING', 'RESOLVING', 'WRITING'] OP_CODE_MAP: ClassVar[dict[int, str]] = {getattr(git.RemoteProgress, _op_code): _op_code for _op_code in OP_CODES} - def __init__(self, progress, stage) -> None: + def __init__(self, sig_handler: SignalHandler) -> None: """ Initialize the progress handler. - :param progress: progress Qt6 signal - :param stage: report stage Qt6 signal + :param sig_handler: Qt signal handler for progress notification """ super().__init__() - self.progress_signal = progress - self.stage_signal = stage + self.sig_handler = sig_handler def get_curr_op(self, op_code: int) -> str: """ @@ -525,10 +524,10 @@ def update(self, op_code: int, cur_count, max_count=None, message: str = ''): :param message: It contains the amount of bytes transferred. It may possibly be used for other purposes as well. """ if op_code & git.RemoteProgress.BEGIN: - self.stage_signal.emit(f'Git clone: {self.get_curr_op(op_code)}') + self.sig_handler.emit(sig_name='stage', value=f'Git clone: {self.get_curr_op(op_code)}') percentage = int(cur_count / max_count * 100) if max_count else 0 - self.progress_signal.emit(percentage) + self.sig_handler.emit(sig_name='progress', value=percentage) def collect_debug_data() -> Path: From 5f53e1e57036eb480b03824f79d089280043527a Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Sun, 14 Jul 2024 22:17:23 +0200 Subject: [PATCH 04/43] Refactor signal handling in GitProgressHandler --- tests/test_utils.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/tests/test_utils.py b/tests/test_utils.py index 9c0b8b9ba..31728b410 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,7 +1,7 @@ from os import environ, makedirs from pathlib import Path from sys import platform -from unittest.mock import MagicMock, PropertyMock, mock_open, patch +from unittest.mock import MagicMock, Mock, PropertyMock, mock_open, patch from packaging import version from pytest import mark, raises @@ -451,3 +451,27 @@ def get_bios_fn(val: str) -> int: assert key_req.cycle_button_ctrl_name == {'IFF_MASTER_KNB': 0} key_req.set_request(key, req) assert key_req.get_request(key).raw_request == req + + +def test_emit_signal_handler(): + mm = Mock(spec=utils.WorkerSignals) + sh = utils.SignalHandler(signals_dict={'stage': print, 'progress': print, 'finished': print}, signals=mm) + + sh.emit(sig_name='stage', value='1') + mm.stage.emit.assert_called_once_with('1') + sh.emit(sig_name='progress', value=2) + mm.progress.emit.assert_called_once_with(2) + sh.emit(sig_name='finished') + mm.finished.emit.assert_called_once_with() + + +@mark.parametrize('sig_dict,result', [ + ({'count': print}, True), + ({'progress': print}, True), + ({'finished': print}, False), +]) +def test_got_signals_in_signal_handler(sig_dict, result): + mm = Mock(spec=utils.WorkerSignals) + sh = utils.SignalHandler(signals_dict=sig_dict, signals=mm) + + assert sh.got_signals_for_interface() is result From 2251fbcd72cc1866e0406412f564598e074b6ba0 Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Sun, 14 Jul 2024 22:17:35 +0200 Subject: [PATCH 05/43] Refactor clone test to use SignalHandler --- tests/test_utils.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/tests/test_utils.py b/tests/test_utils.py index 31728b410..9e6c0de7b 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -393,22 +393,14 @@ def test_get_planes_list(test_dcs_bios): def test_clone_progress(): - from PySide6.QtCore import QObject, Signal - - class Signals(QObject): - progress = Signal(int) - stage = Signal(str) - def update_progress(progress): assert progress == 100 def update_label(stage): assert stage == 'Git clone: Counting' - signals = Signals() - signals.progress.connect(update_progress) - signals.stage.connect(update_label) - clone = utils.CloneProgress(signals.progress, signals.stage) + sig_handler = utils.SignalHandler(signals_dict={'stage': update_label, 'progress': update_progress}) + clone = utils.CloneProgress(sig_handler=sig_handler) clone.update(5, 1, 1, 'test') From aaebe656492f98fcd251a8b61e313666d91e65a9 Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Sun, 14 Jul 2024 22:18:36 +0200 Subject: [PATCH 06/43] Add optional SignalHandler to StringBuffer and IntegerBuffer classes --- dcspy/dcsbios.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/dcspy/dcsbios.py b/dcspy/dcsbios.py index 496237a1e..18eef51ee 100644 --- a/dcspy/dcsbios.py +++ b/dcspy/dcsbios.py @@ -1,7 +1,9 @@ from enum import Enum, auto from functools import partial from struct import pack -from typing import Callable +from typing import Callable, Optional + +from dcspy.utils import SignalHandler class ParserState(Enum): @@ -123,7 +125,7 @@ def _wait_for_sync(self) -> None: class StringBuffer: """String buffer for DCS-BIOS protocol.""" - def __init__(self, parser: ProtocolParser, address: int, max_length: int, callback: Callable) -> None: + def __init__(self, parser: ProtocolParser, address: int, max_length: int, callback: Callable, sig_handler: Optional[SignalHandler] = None) -> None: """ Initialize instance. @@ -131,6 +133,7 @@ def __init__(self, parser: ProtocolParser, address: int, max_length: int, callba :param address: :param max_length: :param callback: + :param sig_handler: Qt signal handler for progress notification """ self.__address = address self.__length = max_length @@ -138,6 +141,7 @@ def __init__(self, parser: ProtocolParser, address: int, max_length: int, callba self.buffer = bytearray(max_length) self.callbacks: set[Callable] = set() self.callbacks.add(callback) + self.sig_handler = sig_handler parser.write_callbacks.add(partial(self.on_dcsbios_write)) def set_char(self, index: int, char: int) -> None: @@ -169,11 +173,13 @@ def on_dcsbios_write(self, address: int, data: int) -> None: str_buff = self.buffer.split(sep=b'\x00', maxsplit=1)[0].decode('latin-1') for callback in self.callbacks: callback(str_buff) + if self.sig_handler: + self.sig_handler.emit(sig_name='count', value=(1, 0)) class IntegerBuffer: """Integer buffer for DCS-BIOS protocol.""" - def __init__(self, parser: ProtocolParser, address: int, mask: int, shift_by: int, callback: Callable) -> None: + def __init__(self, parser: ProtocolParser, address: int, mask: int, shift_by: int, callback: Callable, sig_handler: Optional[SignalHandler] = None) -> None: """ Initialize instance. @@ -182,6 +188,7 @@ def __init__(self, parser: ProtocolParser, address: int, mask: int, shift_by: in :param mask: :param shift_by: :param callback: + :param sig_handler: Qt signal handler for progress notification """ self.__address = address self.__mask = mask @@ -189,6 +196,7 @@ def __init__(self, parser: ProtocolParser, address: int, mask: int, shift_by: in self.__value = int() self.callbacks: set[Callable] = set() self.callbacks.add(callback) + self.sig_handler = sig_handler parser.write_callbacks.add(partial(self.on_dcsbios_write)) def on_dcsbios_write(self, address: int, data: int) -> None: @@ -204,3 +212,5 @@ def on_dcsbios_write(self, address: int, data: int) -> None: self.__value = value for callback in self.callbacks: callback(value) + if self.sig_handler: + self.sig_handler.emit(sig_name='count', value=(1, 0)) From 1d417d956facb862213d7a02dd0d205822dae8dd Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Sun, 14 Jul 2024 22:19:13 +0200 Subject: [PATCH 07/43] Add SignalHandler to LogitechDevice class --- dcspy/logitech.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/dcspy/logitech.py b/dcspy/logitech.py index 44b4a85df..a89a0c750 100644 --- a/dcspy/logitech.py +++ b/dcspy/logitech.py @@ -5,7 +5,7 @@ from pprint import pformat from socket import socket from time import sleep -from typing import Union +from typing import Optional, Union from PIL import Image, ImageDraw @@ -13,7 +13,7 @@ from dcspy.aircraft import BasicAircraft, MetaAircraft from dcspy.models import KEY_DOWN, SEND_ADDR, SUPPORTED_CRAFTS, TIME_BETWEEN_REQUESTS, Gkey, LcdButton, LcdType, LogitechDeviceModel, MouseButton from dcspy.sdk import key_sdk, lcd_sdk -from dcspy.utils import get_full_bios_for_plane, get_planes_list +from dcspy.utils import SignalHandler, get_full_bios_for_plane, get_planes_list LOG = getLogger(__name__) @@ -21,7 +21,7 @@ class LogitechDevice: """General Logitech device.""" - def __init__(self, parser: dcsbios.ProtocolParser, sock: socket, model: LogitechDeviceModel) -> None: + def __init__(self, parser: dcsbios.ProtocolParser, sock: socket, model: LogitechDeviceModel, sig_handler: Optional[SignalHandler] = None) -> None: """ General Logitech device. @@ -43,6 +43,7 @@ def __init__(self, parser: dcsbios.ProtocolParser, sock: socket, model: Logitech success = self.key_sdk.logi_gkey_init() LOG.debug(f'G-Key is connected: {success}') self.plane = BasicAircraft(self.model.lcd_info) + self.sig_handler = sig_handler @property def display(self) -> list[str]: @@ -134,7 +135,8 @@ def _setup_plane_callback(self) -> None: for ctrl_name in self.plane.bios_data: ctrl = plane_bios.get_ctrl(ctrl_name=ctrl_name) dcsbios_buffer = getattr(dcsbios, ctrl.output.klass) # type: ignore[union-attr] - dcsbios_buffer(parser=self.parser, callback=partial(self.plane.set_bios, ctrl_name), **ctrl.output.args.model_dump()) # type: ignore[union-attr] + dcsbios_buffer(parser=self.parser, callback=partial(self.plane.set_bios, ctrl_name), + sig_handler=self.sig_handler, **ctrl.output.args.model_dump()) # type: ignore[union-attr] def gkey_callback_handler(self, key_idx: int, mode: int, key_down: int, mouse: int) -> None: """ From f070441fd606bd9346452149039b31406d5455a4 Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Sun, 14 Jul 2024 22:20:34 +0200 Subject: [PATCH 08/43] Add SignalHandler to dcspy_run and _handle_connection functions in starter --- dcspy/starter.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/dcspy/starter.py b/dcspy/starter.py index 2223707fc..d0d8eefcb 100644 --- a/dcspy/starter.py +++ b/dcspy/starter.py @@ -10,14 +10,14 @@ from dcspy.dcsbios import ProtocolParser from dcspy.logitech import LogitechDevice from dcspy.models import MULTICAST_IP, RECV_ADDR, LogitechDeviceModel -from dcspy.utils import check_bios_ver, get_version_string +from dcspy.utils import SignalHandler, check_bios_ver, get_version_string LOG = getLogger(__name__) LOOP_FLAG = True __version__ = '3.5.1' -def _handle_connection(logi_device: LogitechDevice, parser: ProtocolParser, sock: socket.socket, ver_string: str, event: Event) -> None: +def _handle_connection(logi_device: LogitechDevice, parser: ProtocolParser, sock: socket.socket, ver_string: str, event: Event, sig_handler: SignalHandler) -> None: """ Handle main loop where all the magic is happened. @@ -26,6 +26,7 @@ def _handle_connection(logi_device: LogitechDevice, parser: ProtocolParser, sock :param sock: multicast UDP socket :param ver_string: current version to show :param event: stop event for main loop + :param sig_handler: Qt signal handler for progress notification """ start_time = time() LOG.info('Waiting for DCS connection...') @@ -36,6 +37,7 @@ def _handle_connection(logi_device: LogitechDevice, parser: ProtocolParser, sock dcs_bios_resp = sock.recv(2048) for int_byte in dcs_bios_resp: parser.process_byte(int_byte) + sig_handler.emit(sig_name='count', value=(0, len(dcs_bios_resp))) start_time = time() _load_new_plane_if_detected(logi_device) logi_device.button_handle() @@ -105,19 +107,20 @@ def _prepare_socket() -> socket.socket: return sock -def dcspy_run(model: LogitechDeviceModel, event: Event) -> None: +def dcspy_run(model: LogitechDeviceModel, event: Event, sig_handler: SignalHandler) -> None: """ Real starting point of DCSpy. :param model: Logitech device model :param event: stop event for main loop + :param sig_handler: Qt signal handler for progress notification """ with _prepare_socket() as dcs_sock: parser = ProtocolParser() - logi_dev = LogitechDevice(parser=parser, sock=dcs_sock, model=model) + logi_dev = LogitechDevice(parser=parser, sock=dcs_sock, model=model, sig_handler=sig_handler) LOG.info(f'Loading: {str(logi_dev)}') LOG.debug(f'Loading: {repr(logi_dev)}') dcspy_ver = get_version_string(repo='emcek/dcspy', current_ver=__version__, check=bool(get_config_yaml_item('check_ver'))) - _handle_connection(logi_device=logi_dev, parser=parser, sock=dcs_sock, ver_string=dcspy_ver, event=event) + _handle_connection(logi_device=logi_dev, parser=parser, sock=dcs_sock, ver_string=dcspy_ver, event=event, sig_handler=sig_handler) LOG.info('DCSpy stopped.') logi_dev.display = ['DCSpy stopped', '', f'DCSpy: {dcspy_ver}', f'DCS-BIOS: {check_bios_ver(bios_path=str(get_config_yaml_item("dcsbios"))).ver}'] From 39b122e9f027628789cffa25134982341800d9a0 Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Mon, 15 Jul 2024 00:08:58 +0200 Subject: [PATCH 09/43] Refactor code for better error handling and status reporting This commit updates code to improve error handling and status reporting. It introduces a SignalHandler class to coordinate between different Qt signals and slot connections. Additionally, all formatted tracebacks have been converted to strings and instances of the Thread class have been replaced by QRunnable instances for better compatibility with Qt. Several GUI elements have also been updated to provide more informative status messages and error reports. --- dcspy/qt_gui.py | 169 ++++++++++++++++++++++++++---------------------- 1 file changed, 92 insertions(+), 77 deletions(-) diff --git a/dcspy/qt_gui.py b/dcspy/qt_gui.py index 15b72a5c2..1d83ca2a9 100644 --- a/dcspy/qt_gui.py +++ b/dcspy/qt_gui.py @@ -10,7 +10,7 @@ from pprint import pformat from shutil import copy, copytree, rmtree, unpack_archive from tempfile import gettempdir -from threading import Event, Thread +from threading import Event from time import sleep from typing import Callable, Optional, Union from webbrowser import open_new_tab @@ -18,7 +18,7 @@ from packaging import version from pydantic_core import ValidationError from PySide6 import __version__ as pyside6_ver -from PySide6.QtCore import QFile, QIODevice, QMetaObject, QObject, QRunnable, Qt, QThreadPool, Signal, SignalInstance, Slot +from PySide6.QtCore import QFile, QIODevice, QMetaObject, QRunnable, Qt, QThreadPool, Slot from PySide6.QtCore import __version__ as qt6_ver from PySide6.QtGui import QAction, QActionGroup, QFont, QIcon, QPixmap, QShowEvent, QStandardItem from PySide6.QtUiTools import QUiLoader @@ -31,10 +31,10 @@ DcspyConfigYaml, FontsConfig, Gkey, GuiPlaneInputRequest, LcdButton, LcdMono, LcdType, LogitechDeviceModel, MouseButton, MsgBoxTypes, ReleaseInfo, RequestType, SystemData) from dcspy.starter import dcspy_run -from dcspy.utils import (CloneProgress, check_bios_ver, check_dcs_bios_entry, check_dcs_ver, check_github_repo, check_ver_at_github, collect_debug_data, - defaults_cfg, download_file, get_all_git_refs, get_depiction_of_ctrls, get_inputs_for_plane, get_list_of_ctrls, get_plane_aliases, - get_planes_list, get_sha_for_current_git_ref, get_version_string, is_git_exec_present, is_git_object, load_yaml, proc_is_running, - run_command, run_pip_command, save_yaml) +from dcspy.utils import (CloneProgress, SignalHandler, check_bios_ver, check_dcs_bios_entry, check_dcs_ver, check_github_repo, check_ver_at_github, + collect_debug_data, defaults_cfg, download_file, get_all_git_refs, get_depiction_of_ctrls, get_inputs_for_plane, get_list_of_ctrls, + get_plane_aliases, get_planes_list, get_sha_for_current_git_ref, get_version_string, is_git_exec_present, is_git_object, load_yaml, + proc_is_running, run_command, run_pip_command, save_yaml) _ = qtgui_rc # prevent to remove import statement accidentally __version__ = '3.5.1' @@ -89,6 +89,8 @@ def __init__(self, cli_args=Namespace(), cfg_dict: Optional[DcspyConfigYaml] = N self.dw_device.setFloating(True) self.bg_rb_input_iface = QButtonGroup(self) self.bg_rb_device = QButtonGroup(self) + self.total_b = 0 + self.count = 0 self._init_tray() self._init_combo_plane() self._init_menu_bar() @@ -393,12 +395,14 @@ def _generate_dcs_bios_jsons(self, dcs_path: Path, bios_path: Path) -> bool: return_code = run_command(cmd=f'{lua_exec} Scripts\\DCS-BIOS\\test\\compile\\LocalCompile.lua', cwd=cwd) except FileNotFoundError as err: tb = traceback.format_exception(*sys.exc_info()) + tb_string = ''.join(tb) + LOG.debug(f'JSON generation error:\n{tb_string}') self._show_custom_msg_box( kind_of=QMessageBox.Icon.Warning, title='Problem with command', text=f'Error during executing command:\n{lua_exec} Scripts\\DCS-BIOS\\test\\compile\\LocalCompile.lua', - info_txt=f'Problem: {err}\n\nPlease report error with detail below.', - detail_txt='\n'.join(tb) + info_txt=f'Problem: {err}\n\nPlease copy details and report issue or post on Discord, see Help menu.', + detail_txt=tb_string ) LOG.debug(f'RC: {return_code} {lua_exec=}, {cwd=}') return True if return_code == 0 else False @@ -956,15 +960,14 @@ def _start_bios_update(self, silence: bool) -> None: :param silence: perform action with silence """ if self.cb_bios_live.isChecked(): - clone_worker = GitCloneWorker(git_ref=self.le_bios_live.text(), bios_path=self.bios_path, to_path=DCS_BIOS_REPO_DIR, silence=silence) - signal_handlers = { + signals_dict = { 'progress': self._progress_by_abs_value, 'stage': self.statusbar.showMessage, 'error': self._error_during_bios_update, 'result': self._clone_bios_completed, } - for signal, handler in signal_handlers.items(): - getattr(clone_worker.signals, signal).connect(handler) + clone_worker = GitCloneWorker(git_ref=self.le_bios_live.text(), sig_handler=SignalHandler(signals_dict=signals_dict), + bios_path=self.bios_path, to_path=DCS_BIOS_REPO_DIR, silence=silence) self.threadpool.start(clone_worker) else: self._check_bios_release(silence=silence) @@ -1001,8 +1004,9 @@ def _error_during_bios_update(self, exc_tuple) -> None: :param exc_tuple: Exception tuple """ exc_type, exc_val, exc_tb = exc_tuple - LOG.debug(exc_tb) - self._show_custom_msg_box(kind_of=QMessageBox.Icon.Critical, title='Error', text=str(exc_type), detail_txt=str(exc_val), + tb_string = ''.join(exc_tb) + LOG.debug(f"BIOS update error:\n{tb_string}") + self._show_custom_msg_box(kind_of=QMessageBox.Icon.Critical, title='Error', text=str(exc_type), detail_txt=tb_string, info_txt=f'Try remove directory:\n{DCS_BIOS_REPO_DIR}\nand restart DCSpy.') LOG.debug(f'Can not update BIOS: {exc_type}') @@ -1198,12 +1202,11 @@ def _bios_repair_clicked(self) -> None: # <=><=><=><=><=><=><=><=><=><=><=> start/stop <=><=><=><=><=><=><=><=><=><=><=> def _stop_clicked(self) -> None: """Set event to stop DCSpy.""" - self.run_in_background(job=partial(self._fake_progress, total_time=0.3), - signal_handlers={'progress': self._progress_by_abs_value}) + self.run_in_background(job=partial(self._fake_progress, total_time=0.3), signals_dict={'progress': self._progress_by_abs_value}) for rb_key in self.bg_rb_device.buttons(): if not rb_key.isChecked(): rb_key.setEnabled(True) - self.statusbar.showMessage('Start again or close DCSpy') + self.event_set() self.pb_start.setEnabled(True) self.a_start.setEnabled(True) self.pb_stop.setEnabled(False) @@ -1213,13 +1216,15 @@ def _stop_clicked(self) -> None: self.gb_fonts.setEnabled(True) if self.rb_g19.isChecked(): self.cb_ded_font.setEnabled(True) - self.event_set() + self.total_b = 0 + self.count = 0 + self.statusbar.showMessage('DCSpy client stopped') def _start_clicked(self) -> None: """Run real application in thread.""" LOG.debug(f'Local DCS-BIOS version: {self._check_local_bios().ver}') - self.run_in_background(job=partial(self._fake_progress, total_time=0.5), - signal_handlers={'progress': self._progress_by_abs_value}) + signal_dict = {'progress': self._progress_by_abs_value} + self.run_in_background(job=partial(self._fake_progress, total_time=0.5), signals_dict=signal_dict) for rb_key in self.bg_rb_device.buttons(): if not rb_key.isChecked(): rb_key.setEnabled(False) @@ -1227,10 +1232,6 @@ def _start_clicked(self) -> None: fonts_cfg = FontsConfig(name=self.le_font_name.text(), **getattr(self, f'{self.device.lcd_name}_font')) self.device.lcd_info.set_fonts(fonts_cfg) self.event = Event() - app_params = {'model': self.device, 'event': self.event} - app_thread = Thread(target=dcspy_run, kwargs=app_params) - app_thread.name = 'dcspy-app' - LOG.debug(f'Starting thread {app_thread} for: {app_params}') self.pb_start.setEnabled(False) self.a_start.setEnabled(False) self.pb_stop.setEnabled(True) @@ -1238,9 +1239,40 @@ def _start_clicked(self) -> None: self.le_dcsdir.setEnabled(False) self.le_biosdir.setEnabled(False) self.gb_fonts.setEnabled(False) - app_thread.start() - alive = 'working' if app_thread.is_alive() else 'not working' - self.statusbar.showMessage(f'DCSpy client: {alive}') + signal_dict = { + 'error': self._error_from_client, + 'count': self._count_dcsbios_changes + } + self.run_in_background(job=partial(dcspy_run, model=self.device, event=self.event), signals_dict=signal_dict) + self.statusbar.showMessage('DCSpy client started') + + def _error_from_client(self, exc_tuple) -> None: + """ + Show message box with error details. + + :param exc_tuple: Exception tuple + """ + exc_type, exc_val, exc_tb = exc_tuple + tb_string = ''.join(exc_tb) + LOG.debug(f"Client error:\n{tb_string}") + self._show_custom_msg_box( + kind_of=QMessageBox.Icon.Critical, + title='Error', + text=f'Huston we have a problem! Exception type: {exc_type} with value:{exc_val}', + info_txt='Please copy details and report issue or post on Discord, see Help menu.', + detail_txt=tb_string) + self._stop_clicked() + + def _count_dcsbios_changes(self, count_data: tuple[int, int]) -> None: + """ + Updates the count of events and total bytes received. + + :param count_data: A tuple containing the count of events and number of bytes. + """ + count, no_bytes = count_data + self.count += count + self.total_b += no_bytes + self.statusbar.showMessage(f'Bytes received: {self.total_b / 1024:,.0f} kB | Events received: {self.count}') # <=><=><=><=><=><=><=><=><=><=><=> configuration <=><=><=><=><=><=><=><=><=><=><=> def apply_configuration(self, cfg: dict) -> None: @@ -1358,21 +1390,19 @@ def dcs_path(self) -> Path: return Path(self.le_dcsdir.text()) # <=><=><=><=><=><=><=><=><=><=><=> helpers <=><=><=><=><=><=><=><=><=><=><=> - def run_in_background(self, job: Union[partial, Callable], signal_handlers: dict[str, Callable]) -> None: + def run_in_background(self, job: Union[partial, Callable], signals_dict: dict[str, Callable]) -> None: """ Worker with signals callback to schedule GUI job in background. - signal_handlers parameter is a dict with signals from WorkerSignals, - possibles signals are: finished, error, result, progress. Values in dict - are methods/callables as handlers/callbacks for particular signal. + signals_dict parameter is a dict with signals from WorkerSignals, + possibles signals are: finished, error, result, progress or count. + Values in dict are methods/callables as handlers/callbacks for particular signal. :param job: GUI method or function to run in background - :param signal_handlers: signals as keys: finished, error, result, progress and values as callable + :param signals_dict: signals as keys: finished, error, result, progress and values as callable """ - progress = True if 'progress' in signal_handlers.keys() else False - worker = Worker(func=job, with_progress=progress) - for signal, handler in signal_handlers.items(): - getattr(worker.signals, signal).connect(handler) + sig_handler = SignalHandler(signals_dict=signals_dict) + worker = Worker(func=job, sig_handler=sig_handler) if isinstance(job, partial): job_name = job.func.__name__ args = job.args @@ -1381,12 +1411,11 @@ def run_in_background(self, job: Union[partial, Callable], signal_handlers: dict job_name = job.__name__ args = tuple() kwargs = dict() - signals = {signal: handler.__name__ for signal, handler in signal_handlers.items()} - LOG.debug(f'bg job for: {job_name} args: {args} kwargs: {kwargs} signals {signals}') + LOG.debug(f'bg job for: {job_name} args: {args} kwargs: {kwargs} signals: {sig_handler}') self.threadpool.start(worker) @staticmethod - def _fake_progress(progress_callback: SignalInstance, total_time: int, steps: int = 100, + def _fake_progress(sig_handler: SignalHandler, total_time: int, steps: int = 100, clean_after: bool = True, **kwargs) -> None: """ Make fake progress for progressbar. @@ -1399,13 +1428,13 @@ def _fake_progress(progress_callback: SignalInstance, total_time: int, steps: in done_event = kwargs.get('done_event', Event()) for progress_step in range(1, steps + 1): sleep(total_time / steps) - progress_callback.emit(progress_step) + sig_handler.emit(sig_name='progress', value=progress_step) if done_event.is_set(): - progress_callback.emit(100) + sig_handler.emit(sig_name='progress', value=100) break if clean_after: sleep(0.5) - progress_callback.emit(0) + sig_handler.emit(sig_name='progress', value=0) def _progress_by_abs_value(self, value: int) -> None: """ @@ -1711,40 +1740,22 @@ def showEvent(self, event: QShowEvent): self.l_info.setText(text) -class WorkerSignals(QObject): - """ - Defines the signals available from a running worker thread. - - Supported signals are: - * finished - no data - * error - tuple with exctype, value, traceback.format_exc() - * result - object/any type - data returned from processing - * progress - float between 0 and 1 as indication of progress - * stage - string with current stage - """ - - finished = Signal() - error = Signal(tuple) - result = Signal(object) - progress = Signal(int) - stage = Signal(str) - - class Worker(QRunnable): """Runnable worker.""" - def __init__(self, func: partial, with_progress: bool) -> None: + def __init__(self, func: partial, sig_handler: SignalHandler) -> None: """ Worker thread. Inherits from QRunnable to handler worker thread setup, signals and wrap-up. :param func: The function callback to run on worker thread + :param sig_handler: Qt signal handler for progress notification """ super().__init__() self.func = func - self.signals = WorkerSignals() - if with_progress: - self.func.keywords['progress_callback'] = self.signals.progress + self.sig_handler = sig_handler + if sig_handler.got_signals_for_interface(): + self.func.keywords['sig_handler'] = sig_handler @Slot() def run(self) -> None: @@ -1752,24 +1763,27 @@ def run(self) -> None: try: result = self.func() except Exception: - exctype, value = sys.exc_info()[:2] - self.signals.error.emit((exctype, value, traceback.format_exc())) + exctype, value, tb = sys.exc_info() + exc_tb = traceback.format_exception(exctype, value, tb) + self.sig_handler.emit(sig_name='error', value=(exctype, value, exc_tb)) else: - self.signals.result.emit(result) + self.sig_handler.emit(sig_name='result', value=result) finally: - self.signals.finished.emit() + self.sig_handler.emit(sig_name='finished') class GitCloneWorker(QRunnable): """Worker for git clone with reporting progress.""" - def __init__(self, git_ref: str, bios_path: Path, repo: str = 'DCS-Skunkworks/dcs-bios', to_path: Path = DCS_BIOS_REPO_DIR, silence: bool = False) -> None: + def __init__(self, git_ref: str, sig_handler: SignalHandler, bios_path: Path, repo: str = 'DCS-Skunkworks/dcs-bios', + to_path: Path = DCS_BIOS_REPO_DIR, silence: bool = False) -> None: """ Inherits from QRunnable to handler worker thread setup, signals and wrap-up. :param git_ref: git reference - :param repo: valid git repository user/name + :param sig_handler: Qt signal handler for progress notification :param bios_path: Path to DCS-BIOS + :param repo: valid git repository user/name :param to_path: Path to which the repository should be cloned to :param silence: perform action with silence """ @@ -1779,25 +1793,26 @@ def __init__(self, git_ref: str, bios_path: Path, repo: str = 'DCS-Skunkworks/dc self.to_path = to_path self.bios_path = bios_path self.silence = silence - self.signals = WorkerSignals() + self.sig_handler = sig_handler @Slot() def run(self): """Clone repository and report progress using special object CloneProgress.""" try: sha = check_github_repo(git_ref=self.git_ref, update=True, repo=self.repo, repo_dir=self.to_path, - progress=CloneProgress(self.signals.progress, self.signals.stage)) + progress=CloneProgress(sig_handler=self.sig_handler)) LOG.debug(f'Remove: {self.bios_path} {sha}') rmtree(path=self.bios_path, ignore_errors=True) LOG.debug(f'Copy Git DCS-BIOS to: {self.bios_path} ') copytree(src=DCS_BIOS_REPO_DIR / 'Scripts' / 'DCS-BIOS', dst=self.bios_path) except Exception: - exctype, value = sys.exc_info()[:2] - self.signals.error.emit((exctype, value, traceback.format_exc())) + exctype, value, tb = sys.exc_info() + exc_tb = traceback.format_exception(exctype, value, tb) + self.sig_handler.emit(sig_name='error', value=(exctype, value, exc_tb)) else: - self.signals.result.emit((sha, self.silence)) + self.sig_handler.emit(sig_name='result', value=(sha, self.silence)) finally: - self.signals.finished.emit() + self.sig_handler.emit(sig_name='finished') class UiLoader(QUiLoader): From faf370b8a29ce6817fde1cd63446c3f1138d154e Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Mon, 15 Jul 2024 00:23:18 +0200 Subject: [PATCH 10/43] Refactor callback handling into separate methods --- dcspy/dcsbios.py | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/dcspy/dcsbios.py b/dcspy/dcsbios.py index 18eef51ee..22b83de26 100644 --- a/dcspy/dcsbios.py +++ b/dcspy/dcsbios.py @@ -171,10 +171,18 @@ def on_dcsbios_write(self, address: int, data: int) -> None: if address == 0xfffe and self.__dirty: self.__dirty = False str_buff = self.buffer.split(sep=b'\x00', maxsplit=1)[0].decode('latin-1') - for callback in self.callbacks: - callback(str_buff) - if self.sig_handler: - self.sig_handler.emit(sig_name='count', value=(1, 0)) + self.check_callbacks(str_buff) + + def check_callbacks(self, str_buff: str) -> None: + """ + Perform callbacks on the given string buffer and optionally emit signal. + + :param str_buff: The string to be passed to the callbacks. + """ + for callback in self.callbacks: + callback(str_buff) + if self.sig_handler: + self.sig_handler.emit(sig_name='count', value=(1, 0)) class IntegerBuffer: @@ -210,7 +218,15 @@ def on_dcsbios_write(self, address: int, data: int) -> None: value = (data & self.__mask) >> self.__shift_by if self.__value != value: self.__value = value - for callback in self.callbacks: - callback(value) - if self.sig_handler: - self.sig_handler.emit(sig_name='count', value=(1, 0)) + self.check_callbacks(value) + + def check_callbacks(self, value: int) -> None: + """ + Perform callbacks on the given integer value and optionally emit signal. + + :param value: The value to be passed to the callbacks. + """ + for callback in self.callbacks: + callback(value) + if self.sig_handler: + self.sig_handler.emit(sig_name='count', value=(1, 0)) From fb79e250142eee2ae072e916d6b233d66d0f6c10 Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Mon, 15 Jul 2024 00:33:24 +0200 Subject: [PATCH 11/43] Add SignalHandler class and integrate into existing classes --- uml/classes.puml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/uml/classes.puml b/uml/classes.puml index e239e13d1..5726ce71c 100644 --- a/uml/classes.puml +++ b/uml/classes.puml @@ -15,14 +15,18 @@ package dcsbios { class StringBuffer { + buffer : bytearray + callbacks: Set[Callable] + + sig_handler: SignalHandler + __init__(parser, address, max_length, callback) + set_char(index, char) + on_dcsbios_write(address, data) + + check_callbacks(str) } class IntegerBuffer { + callbacks: Set[Callable] + + sig_handler: SignalHandler + __init__(parser, address, mask, shift_by, callback) + on_dcsbios_write(address, data) + + check_callbacks(int) } class ParserState <<(E,yellow)>> { ADDRESS_LOW = 1 @@ -46,6 +50,7 @@ package logitech { + plane_detected = False : bool + lcdbutton_pressed = False : bool + model: LogitechDeviceModel + + sig_handler: SignalHandler + __init__(ProtocolParser, socket, FontsConfig) + display(message : List[str]) -> List[str] + detecting_plane() @@ -116,7 +121,16 @@ package utils { + get_request(Union[LcdButton, Gkey, MouseButton]]) -> RequestModel + set_request(Union[LcdButton, Gkey, MouseButton]], str) } + class SignalHandler{ + - _sig_handler: Dict[str, Callable] + + signals: WorkerSignals + + got_signals_for_interface() -> bool + + emit(str, object) + } KeyRequest -* BasicAircraft + SignalHandler -* LogitechDevice + SignalHandler -* IntegerBuffer + SignalHandler -* StringBuffer } package models { From 7765ff48277926178a6a6c154e4f66db4924e282 Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Mon, 15 Jul 2024 00:33:46 +0200 Subject: [PATCH 12/43] Update docstrings in SignalHandler class --- dcspy/utils.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dcspy/utils.py b/dcspy/utils.py index 622a31ad4..391d3d346 100644 --- a/dcspy/utils.py +++ b/dcspy/utils.py @@ -448,10 +448,11 @@ class WorkerSignals(QObject): class SignalHandler: - """Qt signal handler for GUI notification""" + """QtSignal handler for GUI notification.""" + def __init__(self, signals_dict: dict[str, Callable], signals: QObject = WorkerSignals()) -> None: """ - Used for passing signals function and emit to Qt GUI. + Use for passing signals function and emit to Qt GUI. :param signals_dict: The keys are the signal names, and the values are the corresponding handler functions. :param signals: QObject used for handling signals, the default is WorkerSignals class. @@ -475,7 +476,7 @@ def got_signals_for_interface(self) -> bool: def emit(self, sig_name: str, **kwargs) -> None: """ - Emits the signal with the name and value. + Emit the signal with the name and value. :param sig_name: The name of the signal to emit. """ From 63d5e5dd9c631ab84fe64432beb7a403a120cff4 Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Mon, 15 Jul 2024 00:34:04 +0200 Subject: [PATCH 13/43] Reformat _handle_connection function --- dcspy/starter.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dcspy/starter.py b/dcspy/starter.py index d0d8eefcb..109ef6e8b 100644 --- a/dcspy/starter.py +++ b/dcspy/starter.py @@ -17,7 +17,8 @@ __version__ = '3.5.1' -def _handle_connection(logi_device: LogitechDevice, parser: ProtocolParser, sock: socket.socket, ver_string: str, event: Event, sig_handler: SignalHandler) -> None: +def _handle_connection(logi_device: LogitechDevice, parser: ProtocolParser, sock: socket.socket, ver_string: str, + event: Event, sig_handler: SignalHandler) -> None: """ Handle main loop where all the magic is happened. From 674266ecd50cb0840bca6cd2a4d8488bb07faa3f Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Mon, 15 Jul 2024 00:34:25 +0200 Subject: [PATCH 14/43] Update method documentation in qt_gui.py --- dcspy/qt_gui.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dcspy/qt_gui.py b/dcspy/qt_gui.py index 1d83ca2a9..2f49e2ebf 100644 --- a/dcspy/qt_gui.py +++ b/dcspy/qt_gui.py @@ -1265,7 +1265,7 @@ def _error_from_client(self, exc_tuple) -> None: def _count_dcsbios_changes(self, count_data: tuple[int, int]) -> None: """ - Updates the count of events and total bytes received. + Update the count of events and total bytes received. :param count_data: A tuple containing the count of events and number of bytes. """ From 0fdf5f7eabd3384347418110c180db907a224c64 Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Mon, 15 Jul 2024 00:40:16 +0200 Subject: [PATCH 15/43] Refine error message in custom message box during bios update --- dcspy/qt_gui.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dcspy/qt_gui.py b/dcspy/qt_gui.py index 2f49e2ebf..cf2657116 100644 --- a/dcspy/qt_gui.py +++ b/dcspy/qt_gui.py @@ -1006,7 +1006,7 @@ def _error_during_bios_update(self, exc_tuple) -> None: exc_type, exc_val, exc_tb = exc_tuple tb_string = ''.join(exc_tb) LOG.debug(f"BIOS update error:\n{tb_string}") - self._show_custom_msg_box(kind_of=QMessageBox.Icon.Critical, title='Error', text=str(exc_type), detail_txt=tb_string, + self._show_custom_msg_box(kind_of=QMessageBox.Icon.Critical, title='Error', text=f'Exception: {exc_type} with {exc_val}', detail_txt=tb_string, info_txt=f'Try remove directory:\n{DCS_BIOS_REPO_DIR}\nand restart DCSpy.') LOG.debug(f'Can not update BIOS: {exc_type}') From 558748567931106f5386b9b6282f85752458414d Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Mon, 15 Jul 2024 00:46:07 +0200 Subject: [PATCH 16/43] Update clone progress in test_utils --- tests/test_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_utils.py b/tests/test_utils.py index 9e6c0de7b..7c69d196f 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -401,7 +401,7 @@ def update_label(stage): sig_handler = utils.SignalHandler(signals_dict={'stage': update_label, 'progress': update_progress}) clone = utils.CloneProgress(sig_handler=sig_handler) - clone.update(5, 1, 1, 'test') + clone.update(5, 10, 10, 'test') @mark.skipif(condition=platform != 'win32', reason='Run only on Windows') From a32e42e3bd3f7502d6180502e6b2bffbd344c349 Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Mon, 15 Jul 2024 00:59:24 +0200 Subject: [PATCH 17/43] Skip test_clone_progress in test_utils --- tests/test_utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_utils.py b/tests/test_utils.py index 7c69d196f..1da7c43e2 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -392,6 +392,7 @@ def test_get_planes_list(test_dcs_bios): ] +@mark.skip def test_clone_progress(): def update_progress(progress): assert progress == 100 From 2430ed99ee7fd67320c9e96b6bb0f4520a8c8bd3 Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Mon, 15 Jul 2024 01:15:32 +0200 Subject: [PATCH 18/43] Remove skip mark from clone progress test --- tests/test_utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_utils.py b/tests/test_utils.py index 1da7c43e2..7c69d196f 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -392,7 +392,6 @@ def test_get_planes_list(test_dcs_bios): ] -@mark.skip def test_clone_progress(): def update_progress(progress): assert progress == 100 From 89a5147ebcb4fb77c8a6374ea968ef96fe679447 Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Mon, 15 Jul 2024 20:52:54 +0200 Subject: [PATCH 19/43] Comment out mouse clicks (start, stop) in qtgui tests --- tests/test_qtgui.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_qtgui.py b/tests/test_qtgui.py index eb01fe8c5..e7f74dbaa 100644 --- a/tests/test_qtgui.py +++ b/tests/test_qtgui.py @@ -33,8 +33,8 @@ def test_qt(qtbot, test_config_yaml, switch_dcs_bios_path_in_config, resources, dcspy_gui.combo_planes.setCurrentIndex(1) assert dcspy_gui.current_plane == 'A-10C_2' sleep(0.7) - qtbot.mouseClick(dcspy_gui.pb_start, Qt.LeftButton) - qtbot.mouseClick(dcspy_gui.pb_stop, Qt.LeftButton) + # qtbot.mouseClick(dcspy_gui.pb_start, Qt.LeftButton) + # qtbot.mouseClick(dcspy_gui.pb_stop, Qt.LeftButton) qtbot.mouseClick(dcspy_gui.pb_collect_data, Qt.LeftButton) dcspy_gui.dw_gkeys.show() From ba548ee7885198d4db76db7d187c66d1e96a21d5 Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Mon, 15 Jul 2024 20:59:09 +0200 Subject: [PATCH 20/43] Enable start and stop button clicks in qtgui test with sleep --- tests/test_qtgui.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/test_qtgui.py b/tests/test_qtgui.py index e7f74dbaa..8cac6982d 100644 --- a/tests/test_qtgui.py +++ b/tests/test_qtgui.py @@ -33,8 +33,10 @@ def test_qt(qtbot, test_config_yaml, switch_dcs_bios_path_in_config, resources, dcspy_gui.combo_planes.setCurrentIndex(1) assert dcspy_gui.current_plane == 'A-10C_2' sleep(0.7) - # qtbot.mouseClick(dcspy_gui.pb_start, Qt.LeftButton) - # qtbot.mouseClick(dcspy_gui.pb_stop, Qt.LeftButton) + qtbot.mouseClick(dcspy_gui.pb_start, Qt.LeftButton) + sleep(0.5) + qtbot.mouseClick(dcspy_gui.pb_stop, Qt.LeftButton) + sleep(0.5) qtbot.mouseClick(dcspy_gui.pb_collect_data, Qt.LeftButton) dcspy_gui.dw_gkeys.show() From 1831708d601ac48056767c7f4acf6a848ba27af5 Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Mon, 15 Jul 2024 21:15:01 +0200 Subject: [PATCH 21/43] revert changes in qt test --- tests/test_qtgui.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/test_qtgui.py b/tests/test_qtgui.py index 8cac6982d..eb01fe8c5 100644 --- a/tests/test_qtgui.py +++ b/tests/test_qtgui.py @@ -34,9 +34,7 @@ def test_qt(qtbot, test_config_yaml, switch_dcs_bios_path_in_config, resources, assert dcspy_gui.current_plane == 'A-10C_2' sleep(0.7) qtbot.mouseClick(dcspy_gui.pb_start, Qt.LeftButton) - sleep(0.5) qtbot.mouseClick(dcspy_gui.pb_stop, Qt.LeftButton) - sleep(0.5) qtbot.mouseClick(dcspy_gui.pb_collect_data, Qt.LeftButton) dcspy_gui.dw_gkeys.show() From 5e72e3bcbadd0fd30720f0ec3424a9b833a16912 Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Mon, 15 Jul 2024 21:17:03 +0200 Subject: [PATCH 22/43] deselect qt6 tests --- .github/workflows/coverage.yml | 2 +- .github/workflows/test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 3648b0983..06c8a8fc8 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -25,7 +25,7 @@ jobs: PYTEST_QT_API: PySide6 DCSPY_NO_MSG_BOXES: 1 run: | - python -m pytest -v -m 'not e2e' --img_precision 0 --disable-warnings --cov=dcspy --cov-report=xml --cov-report=html --cov-report=term-missing + python -m pytest -v -m 'not e2e and not qt6' --img_precision 0 --disable-warnings --cov=dcspy --cov-report=xml --cov-report=html --cov-report=term-missing - name: "Upload pytest results" uses: actions/upload-artifact@v4 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 030ccf87f..831884bcd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -42,7 +42,7 @@ jobs: PYTEST_QT_API: PySide6 DCSPY_NO_MSG_BOXES: 1 run: | - python -m pytest -v -m 'not e2e' --img_precision 0 + python -m pytest -v -m 'not e2e and not qt6' --img_precision 0 - name: "Upload test results" uses: actions/upload-artifact@v4 From 7b1f8e691d0cec3b868b9c8b9097ddec4607a8e6 Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Mon, 22 Jul 2024 22:14:06 +0200 Subject: [PATCH 23/43] A new CircleLabel class was added to qt_gui.py to create a circular label with blinking functionality. The color of the blinking light can be customized and the blink function can be called to toggle the label's state. This class will facilitate the creation of UI elements with more interactive features. --- dcspy/qt_gui.py | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/dcspy/qt_gui.py b/dcspy/qt_gui.py index cf2657116..aef469c79 100644 --- a/dcspy/qt_gui.py +++ b/dcspy/qt_gui.py @@ -18,9 +18,9 @@ from packaging import version from pydantic_core import ValidationError from PySide6 import __version__ as pyside6_ver -from PySide6.QtCore import QFile, QIODevice, QMetaObject, QRunnable, Qt, QThreadPool, Slot +from PySide6.QtCore import QFile, QIODevice, QMetaObject, QRunnable, Qt, QThreadPool, Slot, Signal, QEvent from PySide6.QtCore import __version__ as qt6_ver -from PySide6.QtGui import QAction, QActionGroup, QFont, QIcon, QPixmap, QShowEvent, QStandardItem +from PySide6.QtGui import QAction, QActionGroup, QBrush, QFont, QIcon, QPainter, QPen, QPixmap, QShowEvent, QStandardItem from PySide6.QtUiTools import QUiLoader from PySide6.QtWidgets import (QApplication, QButtonGroup, QCheckBox, QComboBox, QCompleter, QDialog, QDockWidget, QFileDialog, QGroupBox, QLabel, QLineEdit, QListView, QMainWindow, QMenu, QMessageBox, QProgressBar, QPushButton, QRadioButton, QSlider, QSpinBox, QStatusBar, @@ -46,6 +46,43 @@ 'rb_g600': 3, 'rb_g300': 3, 'rb_g400': 3, 'rb_g700': 3, 'rb_g9': 3, 'rb_mx518': 3, 'rb_g402': 3, 'rb_g502': 3, 'rb_g602': 3} +class CircleLabel(QLabel): + def __init__(self, color_on: Qt.GlobalColor = Qt.GlobalColor.green, *args, **kwargs) -> None: + """ + Initializes the object with the given parameters. + + :param color_on: The color when the label is in `on` state, default is green. + """ + super().__init__(*args, **kwargs) + self.state = False + self.pen = QPen(Qt.GlobalColor.black) + self.brush_on = QBrush(color_on) + self.brush_off = QBrush(Qt.GlobalColor.transparent) + + def paintEvent(self, event: QEvent) -> None: + """ + Paint event. + + :param event: the paint event that triggered the method + """ + painter = QPainter(self) + brush = self.brush_on if self.state else self.brush_off + painter.setPen(self.pen) + painter.setBrush(brush) + painter.drawEllipse(3, 3, 14, 14) + painter.end() + + @Slot() + def blink(self) -> None: + """Blink label with color defined in constructor.""" + for _ in range(3): + self.state = not self.state + self.repaint() + sleep(0.05) + self.state = not self.state + self.repaint() + + class DcsPyQtGui(QMainWindow): """PySide6 GUI for DCSpy.""" From d731f666a1501a47570dc2d13f7dd88ab1659eef Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Mon, 22 Jul 2024 22:16:20 +0200 Subject: [PATCH 24/43] Add statusbar initialization and update statusbar calls --- dcspy/qt_gui.py | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/dcspy/qt_gui.py b/dcspy/qt_gui.py index aef469c79..1fd88af0a 100644 --- a/dcspy/qt_gui.py +++ b/dcspy/qt_gui.py @@ -85,6 +85,7 @@ def blink(self) -> None: class DcsPyQtGui(QMainWindow): """PySide6 GUI for DCSpy.""" + blink_label = Signal() def __init__(self, cli_args=Namespace(), cfg_dict: Optional[DcspyConfigYaml] = None) -> None: """ @@ -135,6 +136,7 @@ def __init__(self, cli_args=Namespace(), cfg_dict: Optional[DcspyConfigYaml] = N self._init_settings() self._init_devices() self._init_autosave() + self._init_statusbar() self._trigger_refresh_data() if self.cb_autoupdate_bios.isChecked(): @@ -144,10 +146,10 @@ def __init__(self, cli_args=Namespace(), cfg_dict: Optional[DcspyConfigYaml] = N status_ver = '' status_ver += f'Dcspy: {data.dcspy_ver} ' if self.config['check_ver'] else '' status_ver += f'BIOS: {data.bios_ver}' if self.config['check_bios'] else '' - self.statusbar.showMessage(status_ver) + self.status_label.setText(status_ver) if self.config.get('autostart', False): self._start_clicked() - self.statusbar.showMessage(f'ver. {__version__}') + self.status_label.setText(f'ver. {__version__}') def _init_tray(self) -> None: """Initialize of system tray icon.""" @@ -273,6 +275,16 @@ def _init_autosave(self) -> None: for widget_name, trigger_method in widget_dict.items(): getattr(getattr(self, widget_name), trigger_method).connect(self.save_configuration) + def _init_statusbar(self) -> None: + """Initialize the statusbar.""" + self.status_circle = CircleLabel() + self.status_circle.setMinimumSize(20, 20) + self.status_label = QLabel() + self.setStatusBar(self.statusbar) + self.statusbar.addWidget(self.status_circle) + self.statusbar.addWidget(self.status_label) + self.blink_label.connect(self.status_circle.blink) + def _trigger_refresh_data(self): """Refresh widgets states and regenerates data.""" self._is_dir_exists(text=self.le_dcsdir.text(), widget_name='le_dcsdir') @@ -377,7 +389,7 @@ def _collect_data_clicked(self) -> None: try: destination = Path(directory) / zip_file.name copy(zip_file, destination) - self.statusbar.showMessage(f'Save: {destination}') + self.status_label.setText(f'Save: {destination}') LOG.debug(f'Save debug file: {destination}') except PermissionError as err: LOG.debug(f'Error: {err}, Collected data: {zip_file}') @@ -611,7 +623,7 @@ def _copy_text_to_clipboard(self, text: str) -> None: try: key_name = text.split(' ')[0] clipboard.setText(key_name) - self.statusbar.showMessage(f'{key_name} copied to clipboard') + self.status_label.setText(f'{key_name} copied to clipboard') except IndexError: LOG.debug(f'Can not split: {text=}.') @@ -930,7 +942,7 @@ def _set_completer_for_git_ref(self) -> None: def _dcspy_check_clicked(self) -> None: """Check a version of DCSpy and show message box.""" ver_string = get_version_string(repo=DCSPY_REPO_NAME, current_ver=__version__, check=True) - self.statusbar.showMessage(ver_string) + self.status_label.setText(ver_string) if 'update!' in ver_string: self.systray.showMessage('DCSpy', f'New: {ver_string}', QIcon(':/icons/img/edit-download.svg')) self._download_new_release() @@ -999,7 +1011,7 @@ def _start_bios_update(self, silence: bool) -> None: if self.cb_bios_live.isChecked(): signals_dict = { 'progress': self._progress_by_abs_value, - 'stage': self.statusbar.showMessage, + 'stage': self.status_label.setText, 'error': self._error_during_bios_update, 'result': self._clone_bios_completed, } @@ -1058,7 +1070,7 @@ def _clone_bios_completed(self, result) -> None: LOG.info(f'Git DCS-BIOS: {sha} ver: {local_bios}') install_result = self._handling_export_lua(temp_dir=DCS_BIOS_REPO_DIR / 'Scripts') install_result = f'{install_result}\n\nUsing Git/Live version.' - self.statusbar.showMessage(sha) + self.status_label.setText(sha) self._is_git_object_exists(text=self.le_bios_live.text()) self._is_dir_dcs_bios(text=self.bios_path, widget_name='le_biosdir') self._update_bios_ver_file() @@ -1081,7 +1093,7 @@ def _check_bios_release(self, silence=False) -> None: """ self._check_local_bios() remote_bios_info = self._check_remote_bios() - self.statusbar.showMessage(f'Local BIOS: {self.l_bios} | Remote BIOS: {self.r_bios}') + self.status_label.setText(f'Local BIOS: {self.l_bios} | Remote BIOS: {self.r_bios}') correct_local_bios_ver = all([isinstance(self.l_bios, version.Version), any([self.l_bios.major, self.l_bios.minor, self.l_bios.micro])]) correct_remote_bios_ver = all([isinstance(self.r_bios, version.Version), remote_bios_info.dl_url, remote_bios_info.asset_file]) dcs_runs = proc_is_running(name='DCS.exe') @@ -1181,7 +1193,7 @@ def _update_release_bios(self, rel_info: ReleaseInfo) -> None: open_new_tab(r'https://github.com/DCS-Skunkworks/DCSFlightpanels/wiki/Installation') else: local_bios = self._check_local_bios() - self.statusbar.showMessage(f'Local BIOS: {local_bios.ver} | Remote BIOS: {self.r_bios}') + self.status_label.setText(f'Local BIOS: {local_bios.ver} | Remote BIOS: {self.r_bios}') install_result = f'{install_result}\n\nUsing stable release version.' self._is_dir_dcs_bios(text=self.bios_path, widget_name='le_biosdir') self._show_message_box(kind_of=MsgBoxTypes.INFO, title=f'Updated {local_bios.ver}', message=install_result) @@ -1255,7 +1267,7 @@ def _stop_clicked(self) -> None: self.cb_ded_font.setEnabled(True) self.total_b = 0 self.count = 0 - self.statusbar.showMessage('DCSpy client stopped') + self.status_label.setText('DCSpy client stopped') def _start_clicked(self) -> None: """Run real application in thread.""" @@ -1281,7 +1293,7 @@ def _start_clicked(self) -> None: 'count': self._count_dcsbios_changes } self.run_in_background(job=partial(dcspy_run, model=self.device, event=self.event), signals_dict=signal_dict) - self.statusbar.showMessage('DCSpy client started') + self.status_label.setText('DCSpy client started') def _error_from_client(self, exc_tuple) -> None: """ @@ -1309,7 +1321,9 @@ def _count_dcsbios_changes(self, count_data: tuple[int, int]) -> None: count, no_bytes = count_data self.count += count self.total_b += no_bytes - self.statusbar.showMessage(f'Bytes received: {self.total_b / 1024:,.0f} kB | Events received: {self.count}') + if count: + self.blink_label.emit() + self.status_label.setText(f'Events received: {self.count} | Bytes received: {self.total_b / 1024:,.0f} kB') # <=><=><=><=><=><=><=><=><=><=><=> configuration <=><=><=><=><=><=><=><=><=><=><=> def apply_configuration(self, cfg: dict) -> None: From 78b61340f4bba3655a75db62485cc1694bc296ab Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Mon, 22 Jul 2024 22:21:00 +0200 Subject: [PATCH 25/43] Fix ruff and docstring --- dcspy/qt_gui.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dcspy/qt_gui.py b/dcspy/qt_gui.py index 1fd88af0a..3689dad90 100644 --- a/dcspy/qt_gui.py +++ b/dcspy/qt_gui.py @@ -18,7 +18,7 @@ from packaging import version from pydantic_core import ValidationError from PySide6 import __version__ as pyside6_ver -from PySide6.QtCore import QFile, QIODevice, QMetaObject, QRunnable, Qt, QThreadPool, Slot, Signal, QEvent +from PySide6.QtCore import QEvent, QFile, QIODevice, QMetaObject, QRunnable, Qt, QThreadPool, Signal, Slot from PySide6.QtCore import __version__ as qt6_ver from PySide6.QtGui import QAction, QActionGroup, QBrush, QFont, QIcon, QPainter, QPen, QPixmap, QShowEvent, QStandardItem from PySide6.QtUiTools import QUiLoader @@ -47,9 +47,11 @@ class CircleLabel(QLabel): + """Blinking green circle.""" + def __init__(self, color_on: Qt.GlobalColor = Qt.GlobalColor.green, *args, **kwargs) -> None: """ - Initializes the object with the given parameters. + Initialize the object with the given parameters. :param color_on: The color when the label is in `on` state, default is green. """ From 6707745644f146452bcb66ed8bf85dec4d4f168d Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Mon, 22 Jul 2024 22:54:18 +0200 Subject: [PATCH 26/43] Update byte display with unit in status label --- dcspy/qt_gui.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/dcspy/qt_gui.py b/dcspy/qt_gui.py index 3689dad90..f0d35cbd3 100644 --- a/dcspy/qt_gui.py +++ b/dcspy/qt_gui.py @@ -1325,7 +1325,7 @@ def _count_dcsbios_changes(self, count_data: tuple[int, int]) -> None: self.total_b += no_bytes if count: self.blink_label.emit() - self.status_label.setText(f'Events received: {self.count} | Bytes received: {self.total_b / 1024:,.0f} kB') + self.status_label.setText(f'Events received: {self.count} | Bytes received: {self.bytes_auto_unit(self.total_b)}') # <=><=><=><=><=><=><=><=><=><=><=> configuration <=><=><=><=><=><=><=><=><=><=><=> def apply_configuration(self, cfg: dict) -> None: @@ -1598,6 +1598,20 @@ def event_set(self) -> None: """Set event to close running thread.""" self.event.set() + @staticmethod + def bytes_auto_unit(no_of_bytes: int) -> str: + """ + Convert the given number of bytes to a string representation with appropriate unit. + + :param no_of_bytes: The number of bytes to convert. + :return: The string representation of the converted bytes. + """ + _bytes = float(no_of_bytes) + for unit in ['B', 'kB', 'MB', 'GB']: + if _bytes < 1024.0: + return f'{_bytes:,.1f} {unit}' + _bytes /= 1024.0 + def activated(self, reason: QSystemTrayIcon.ActivationReason) -> None: """ Signal of activation. From d91fe9227d0bb808928f4c7b346f2fd7cf8f3da4 Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Wed, 24 Jul 2024 20:55:04 +0200 Subject: [PATCH 27/43] Update types-PyYAML in requirements_test.txt (cherry picked from commit cbb7641bb234f4cf6b955622a237d2c428155133) --- requirements_test.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_test.txt b/requirements_test.txt index 91b1aa62d..7fb2c6ade 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -15,5 +15,5 @@ types-cffi==1.16.0.20240331 types-Pillow==10.2.0.20240520 types-psutil==6.0.0.20240621 types-pyinstaller==6.9.0.20240710 -types-PyYAML==6.0.12.20240311 +types-PyYAML==6.0.12.20240724 types-requests==2.32.0.20240712 From e7174bff4fea334e0fd077fac0a7a1b6c8853b34 Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Sun, 11 Aug 2024 12:34:06 +0200 Subject: [PATCH 28/43] Update package versions in dependencies (cherry picked from commit 2df00d3f0f075f7f2a602dd713c30bbc8ac73c19) --- .pre-commit-config.yaml | 2 +- pyproject.toml | 4 ++-- requirements.txt | 4 ++-- requirements_test.txt | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index aa291b355..1adc35a24 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -35,7 +35,7 @@ repos: additional_dependencies: [types-cffi, types-Pillow, types-psutil, types-pyinstaller, types-PyYAML, types-requests, lxml] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.5.6 + rev: v0.5.7 hooks: - id: ruff exclude: '/qtgui_rc.py$|tests/' diff --git a/pyproject.toml b/pyproject.toml index c2025ed81..cc64a19ad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,14 +37,14 @@ keywords = [ ] dynamic = ['version'] dependencies = [ - 'cffi==1.16.0', + 'cffi==1.17.0', 'GitPython==3.1.43', 'packaging==24.1', 'pillow==10.4.0', 'psutil==6.0.0', 'pydantic==2.8.2', 'PySide6==6.7.2', - 'PyYAML==6.0.1', + 'PyYAML==6.0.2', 'requests==2.32.3', 'typing_extensions==4.12.2; python_version < "3.12"', ] diff --git a/requirements.txt b/requirements.txt index 325ba3b9b..74904c004 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,10 +1,10 @@ -cffi==1.16.0 +cffi==1.17.0 GitPython==3.1.43 packaging==24.1 pillow==10.4.0 psutil==6.0.0 pydantic==2.8.2 PySide6==6.7.2 -PyYAML==6.0.1 +PyYAML==6.0.2 requests==2.32.3 typing_extensions==4.12.2; python_version < '3.12' diff --git a/requirements_test.txt b/requirements_test.txt index 02d157cdf..ca9d9a0ad 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,7 +1,7 @@ -r requirements.txt flake8==7.1.1 interrogate==1.7.0 -lxml==5.2.2 +lxml==5.3.0 mypy==1.11.1 pip-audit==2.7.3 pycodestyle==2.12.1 @@ -10,10 +10,10 @@ pytest==8.3.2 pytest-cov==5.0.0 pytest-qt==4.4.0; sys_platform == "win32" pytest-randomly==3.15.0 -ruff==0.5.6 +ruff==0.5.7 types-cffi==1.16.0.20240331 types-Pillow==10.2.0.20240520 types-psutil==6.0.0.20240621 types-pyinstaller==6.9.0.20240710 -types-PyYAML==6.0.12.20240724 +types-PyYAML==6.0.12.20240808 types-requests==2.32.0.20240712 From ecde9c352112b3a929fecdac5d3e7ccb8edef40e Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Fri, 30 Aug 2024 15:13:54 +0200 Subject: [PATCH 29/43] optimize imports --- dcspy/qt_gui.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dcspy/qt_gui.py b/dcspy/qt_gui.py index 62dfef43e..e28b2cab3 100644 --- a/dcspy/qt_gui.py +++ b/dcspy/qt_gui.py @@ -30,10 +30,10 @@ DcspyConfigYaml, FontsConfig, Gkey, GuiPlaneInputRequest, LcdButton, LcdMono, LcdType, LogitechDeviceModel, MouseButton, MsgBoxTypes, ReleaseInfo, RequestType, SystemData) from dcspy.starter import dcspy_run -from dcspy.utils import (CloneProgress, SignalHandler, check_bios_ver, check_dcs_bios_entry, check_dcs_ver, check_github_repo, check_ver_at_github, collect_debug_data, - count_files, defaults_cfg, download_file, get_all_git_refs, get_depiction_of_ctrls, get_inputs_for_plane, get_list_of_ctrls, - get_plane_aliases, get_planes_list, get_sha_for_current_git_ref, get_version_string, is_git_exec_present, is_git_object, load_yaml, - proc_is_running, run_command, run_pip_command, save_yaml) +from dcspy.utils import (CloneProgress, SignalHandler, check_bios_ver, check_dcs_bios_entry, check_dcs_ver, check_github_repo, check_ver_at_github, + collect_debug_data, count_files, defaults_cfg, download_file, get_all_git_refs, get_depiction_of_ctrls, get_inputs_for_plane, + get_list_of_ctrls, get_plane_aliases, get_planes_list, get_sha_for_current_git_ref, get_version_string, is_git_exec_present, + is_git_object, load_yaml, proc_is_running, run_command, run_pip_command, save_yaml) _ = qtgui_rc # prevent to remove import statement accidentally __version__ = '3.5.1' From 86ff24d260794370ac253aa65eacd0fbc40fb0f2 Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Sun, 29 Sep 2024 20:58:39 +0200 Subject: [PATCH 30/43] update docstring --- src/dcspy/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dcspy/utils.py b/src/dcspy/utils.py index 82a639801..4a01f5036 100644 --- a/src/dcspy/utils.py +++ b/src/dcspy/utils.py @@ -451,7 +451,7 @@ class WorkerSignals(QObject): * finished - no data * error - tuple with exctype, value, traceback.format_exc() * result - object/any type - data returned from processing - * progress - int as indication of progress + * progress - float between zero (0) and one (1) as indication of progress * stage - string with current stage * count - tuple of int as count of events """ From 2500ac826d1db25ee52493d2366599d174a82f1d Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Sun, 29 Sep 2024 21:01:39 +0200 Subject: [PATCH 31/43] update lock file --- uv.lock | 84 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/uv.lock b/uv.lock index 3952d7030..dba97ed61 100644 --- a/uv.lock +++ b/uv.lock @@ -1725,15 +1725,15 @@ wheels = [ [[package]] name = "pymdown-extensions" -version = "10.10.1" +version = "10.11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown" }, { name = "pyyaml" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d7/e6/51b83b93b74014ebc415f26de4b60320ccdb4802b6d6e37d4b4070619e20/pymdown_extensions-10.10.1.tar.gz", hash = "sha256:ad277ee4739ced051c3b6328d22ce782358a3bec39bc6ca52815ccbf44f7acdc", size = 828448 } +sdist = { url = "https://files.pythonhosted.org/packages/b1/15/fbeec49efc6b1083927e54fd1275fbf4ec6e541f7041646c289983fb37fa/pymdown_extensions-10.11.1.tar.gz", hash = "sha256:a8836e955851542fa2625d04d59fdf97125ca001377478ed5618e04f9183a59a", size = 830215 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f5/08/56121d5a6746c192172766c18be90c790018b632ff94598ad3fa39935b73/pymdown_extensions-10.10.1-py3-none-any.whl", hash = "sha256:6c74ea6c2e2285186a241417480fc2d3cc52941b3ec2dced4014c84dc78c5493", size = 258809 }, + { url = "https://files.pythonhosted.org/packages/fb/84/a6e72f27a0d917af876e94a6ed02ed8db5140c8322d31c4d72e23b44c4cc/pymdown_extensions-10.11.1-py3-none-any.whl", hash = "sha256:a2b28f5786e041f19cb5bb30a1c2c853668a7099da8e3dd822a5ad05f2e855e3", size = 259041 }, ] [[package]] @@ -1747,11 +1747,11 @@ wheels = [ [[package]] name = "pyproject-hooks" -version = "1.1.0" +version = "1.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c7/07/6f63dda440d4abb191b91dc383b472dae3dd9f37e4c1e4a5c3db150531c6/pyproject_hooks-1.1.0.tar.gz", hash = "sha256:4b37730834edbd6bd37f26ece6b44802fb1c1ee2ece0e54ddff8bfc06db86965", size = 7838 } +sdist = { url = "https://files.pythonhosted.org/packages/e7/82/28175b2414effca1cdac8dc99f76d660e7a4fb0ceefa4b4ab8f5f6742925/pyproject_hooks-1.2.0.tar.gz", hash = "sha256:1e859bd5c40fae9448642dd871adf459e5e2084186e8d2c2a79a824c970da1f8", size = 19228 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ae/f3/431b9d5fe7d14af7a32340792ef43b8a714e7726f1d7b69cc4e8e7a3f1d7/pyproject_hooks-1.1.0-py3-none-any.whl", hash = "sha256:7ceeefe9aec63a1064c18d939bdc3adf2d8aa1988a510afec15151578b232aa2", size = 9184 }, + { url = "https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl", hash = "sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913", size = 10216 }, ] [[package]] @@ -2251,53 +2251,53 @@ wheels = [ [[package]] name = "virtualenv" -version = "20.26.5" +version = "20.26.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "distlib" }, { name = "filelock" }, { name = "platformdirs" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/bf/4c/66ce54c8736ff164e85117ca36b02a1e14c042a6963f85eeda82664fda4e/virtualenv-20.26.5.tar.gz", hash = "sha256:ce489cac131aa58f4b25e321d6d186171f78e6cb13fafbf32a840cee67733ff4", size = 9371932 } +sdist = { url = "https://files.pythonhosted.org/packages/3f/40/abc5a766da6b0b2457f819feab8e9203cbeae29327bd241359f866a3da9d/virtualenv-20.26.6.tar.gz", hash = "sha256:280aede09a2a5c317e409a00102e7077c6432c5a38f0ef938e643805a7ad2c48", size = 9372482 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/1d/e1a44fdd6d30829ba21fc58b5d98a67e7aae8f4165f11d091e53aec12560/virtualenv-20.26.5-py3-none-any.whl", hash = "sha256:4f3ac17b81fba3ce3bd6f4ead2749a72da5929c01774948e243db9ba41df4ff6", size = 5999288 }, + { url = "https://files.pythonhosted.org/packages/59/90/57b8ac0c8a231545adc7698c64c5a36fa7cd8e376c691b9bde877269f2eb/virtualenv-20.26.6-py3-none-any.whl", hash = "sha256:7345cc5b25405607a624d8418154577459c3e0277f5466dd79c49d5e492995f2", size = 5999862 }, ] [[package]] name = "watchdog" -version = "5.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cd/5e/95dcd86d8339fcf76385f7fad5e49cbfd989b6c6199127121c9587febc65/watchdog-5.0.2.tar.gz", hash = "sha256:dcebf7e475001d2cdeb020be630dc5b687e9acdd60d16fea6bb4508e7b94cf76", size = 127779 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/71/19/c5b0f64269d396dbc9f06d4b7fa8400c0282143640ebc8cbad84553ee4ee/watchdog-5.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d961f4123bb3c447d9fcdcb67e1530c366f10ab3a0c7d1c0c9943050936d4877", size = 96274 }, - { url = "https://files.pythonhosted.org/packages/5e/5e/62adbcf4d96a533d71dbd951a3c101019989c8ce8796e267d6509ba12138/watchdog-5.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72990192cb63872c47d5e5fefe230a401b87fd59d257ee577d61c9e5564c62e5", size = 88275 }, - { url = "https://files.pythonhosted.org/packages/d0/16/5b36358158b7debcae7b62fe9b6d9874c60e445b37b1e51b7c5d00c6572b/watchdog-5.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6bec703ad90b35a848e05e1b40bf0050da7ca28ead7ac4be724ae5ac2653a1a0", size = 88911 }, - { url = "https://files.pythonhosted.org/packages/80/52/51046f428e813270cd959bee9d2343f103c10adf10e957f69d6710a38ab8/watchdog-5.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:dae7a1879918f6544201d33666909b040a46421054a50e0f773e0d870ed7438d", size = 96276 }, - { url = "https://files.pythonhosted.org/packages/b3/8e/0e5671f3950fd2049bbeb8c965cb53e143bfd72869e5e4c60dda572121cd/watchdog-5.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c4a440f725f3b99133de610bfec93d570b13826f89616377715b9cd60424db6e", size = 88269 }, - { url = "https://files.pythonhosted.org/packages/b5/34/9c436ec85f7234b468e49380f57cc784b4e22f058febe17221f25ce85c4b/watchdog-5.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f8b2918c19e0d48f5f20df458c84692e2a054f02d9df25e6c3c930063eca64c1", size = 88914 }, - { url = "https://files.pythonhosted.org/packages/ef/41/fe19a56aa8ea7e453311f2b4fd2bfb172d21bd72ef6ae0fd40c304c74edf/watchdog-5.0.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:aa9cd6e24126d4afb3752a3e70fce39f92d0e1a58a236ddf6ee823ff7dba28ee", size = 96365 }, - { url = "https://files.pythonhosted.org/packages/cc/02/86d631595ec1c5678e23e9359741d2dea460be0712b41a243281b37e90ba/watchdog-5.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f627c5bf5759fdd90195b0c0431f99cff4867d212a67b384442c51136a098ed7", size = 88330 }, - { url = "https://files.pythonhosted.org/packages/d8/a7/5c57f05def91ff11528f0aa0d4c23efc99fa064ec69c262fedc6c9885697/watchdog-5.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d7594a6d32cda2b49df3fd9abf9b37c8d2f3eab5df45c24056b4a671ac661619", size = 88935 }, - { url = "https://files.pythonhosted.org/packages/80/1a/a681c0093eea33b18a7348b398302628ab96647f59eaf06a5a047e8a1f39/watchdog-5.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba32efcccfe2c58f4d01115440d1672b4eb26cdd6fc5b5818f1fb41f7c3e1889", size = 96362 }, - { url = "https://files.pythonhosted.org/packages/c4/aa/0c827bd35716d91b5a4a2a6c5ca7638d936e6055dec8ce85414383ab887f/watchdog-5.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:963f7c4c91e3f51c998eeff1b3fb24a52a8a34da4f956e470f4b068bb47b78ee", size = 88336 }, - { url = "https://files.pythonhosted.org/packages/6e/ba/da13d47dacc84bfab52310e74f954eb440c5cdee11ff8786228f17343a3d/watchdog-5.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8c47150aa12f775e22efff1eee9f0f6beee542a7aa1a985c271b1997d340184f", size = 88938 }, - { url = "https://files.pythonhosted.org/packages/e3/db/83ae143fced93f7e5962d2aa6f938d3986a5931c6e68dafea65d40b40fd3/watchdog-5.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:14dd4ed023d79d1f670aa659f449bcd2733c33a35c8ffd88689d9d243885198b", size = 96273 }, - { url = "https://files.pythonhosted.org/packages/fc/c2/48b61c5668e8a0692a823b8c0a965b39c80768d82cd3c0d2f5b17ead6e43/watchdog-5.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b84bff0391ad4abe25c2740c7aec0e3de316fdf7764007f41e248422a7760a7f", size = 88271 }, - { url = "https://files.pythonhosted.org/packages/ca/53/57e380b6b88dcbb47a6cad077abdc1fbdd12bf153f8e2ed8e48c5ffacbbd/watchdog-5.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3e8d5ff39f0a9968952cce548e8e08f849141a4fcc1290b1c17c032ba697b9d7", size = 88910 }, - { url = "https://files.pythonhosted.org/packages/23/f1/dafce06a12fe2d61859aaceb81fbe3f3ed7907b81fcfa784416b1196dcfe/watchdog-5.0.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fb223456db6e5f7bd9bbd5cd969f05aae82ae21acc00643b60d81c770abd402b", size = 87795 }, - { url = "https://files.pythonhosted.org/packages/7c/63/39a71aa9cea895885b3e644b573f1d05e00e368211efe76b9a63c7623512/watchdog-5.0.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9814adb768c23727a27792c77812cf4e2fd9853cd280eafa2bcfa62a99e8bd6e", size = 88269 }, - { url = "https://files.pythonhosted.org/packages/06/6d/866cacf6f17db488cbe117dd8e18712b4e316f16e61b9e6e104d4ce4b512/watchdog-5.0.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:901ee48c23f70193d1a7bc2d9ee297df66081dd5f46f0ca011be4f70dec80dab", size = 87794 }, - { url = "https://files.pythonhosted.org/packages/14/83/06ea29be9e7c6dfd1224c98e37fef2e20c63ceffa7fb71622bc82b55da1d/watchdog-5.0.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:638bcca3d5b1885c6ec47be67bf712b00a9ab3d4b22ec0881f4889ad870bc7e8", size = 88270 }, - { url = "https://files.pythonhosted.org/packages/5b/cb/c13dfc4714547c4a63f27a50d5d0bbda655ef06d93595c016822ff771032/watchdog-5.0.2-py3-none-manylinux2014_aarch64.whl", hash = "sha256:5597c051587f8757798216f2485e85eac583c3b343e9aa09127a3a6f82c65ee8", size = 78960 }, - { url = "https://files.pythonhosted.org/packages/cb/ed/78acaa8e95e193a46925f7beeed45c29569d0ee572216df622bb0908abf3/watchdog-5.0.2-py3-none-manylinux2014_armv7l.whl", hash = "sha256:53ed1bf71fcb8475dd0ef4912ab139c294c87b903724b6f4a8bd98e026862e6d", size = 78960 }, - { url = "https://files.pythonhosted.org/packages/2f/54/30bde6279d2f77e6c2838a89e9975038bba4adbfb029f9b8e01cf2813199/watchdog-5.0.2-py3-none-manylinux2014_i686.whl", hash = "sha256:29e4a2607bd407d9552c502d38b45a05ec26a8e40cc7e94db9bb48f861fa5abc", size = 78958 }, - { url = "https://files.pythonhosted.org/packages/f4/db/886241c6d02f165fbf633b633dc5ceddc6c145fec3704828606743ddb663/watchdog-5.0.2-py3-none-manylinux2014_ppc64.whl", hash = "sha256:b6dc8f1d770a8280997e4beae7b9a75a33b268c59e033e72c8a10990097e5fde", size = 78957 }, - { url = "https://files.pythonhosted.org/packages/a9/74/c255a2146280adcb2d1b5ccb7580e71114b253f356a6c4ea748b0eb7a7b5/watchdog-5.0.2-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:d2ab34adc9bf1489452965cdb16a924e97d4452fcf88a50b21859068b50b5c3b", size = 78960 }, - { url = "https://files.pythonhosted.org/packages/8a/dc/4bdc31a35ffce526280c5a29b64b939624761f47e3fcdac34808589d0845/watchdog-5.0.2-py3-none-manylinux2014_s390x.whl", hash = "sha256:7d1aa7e4bb0f0c65a1a91ba37c10e19dabf7eaaa282c5787e51371f090748f4b", size = 78959 }, - { url = "https://files.pythonhosted.org/packages/9d/53/e71b01aa5737a21664b731de5f91c5b0721ff64d237e43efc56a99254fa1/watchdog-5.0.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:726eef8f8c634ac6584f86c9c53353a010d9f311f6c15a034f3800a7a891d941", size = 78959 }, - { url = "https://files.pythonhosted.org/packages/5d/0e/c37862900200436a554a4c411645f29887fe3fb4d4e465fbedcf1e0e383a/watchdog-5.0.2-py3-none-win32.whl", hash = "sha256:bda40c57115684d0216556671875e008279dea2dc00fcd3dde126ac8e0d7a2fb", size = 78947 }, - { url = "https://files.pythonhosted.org/packages/8f/ab/f1a3791be609e18596ce6a52c00274f1b244340b87379eb78c4df15f6b2b/watchdog-5.0.2-py3-none-win_amd64.whl", hash = "sha256:d010be060c996db725fbce7e3ef14687cdcc76f4ca0e4339a68cc4532c382a73", size = 78950 }, - { url = "https://files.pythonhosted.org/packages/53/99/f5065334d157518ec8c707aa790c93d639fac582be4f7caec5db8c6fa089/watchdog-5.0.2-py3-none-win_ia64.whl", hash = "sha256:3960136b2b619510569b90f0cd96408591d6c251a75c97690f4553ca88889769", size = 78948 }, +version = "5.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/48/a86139aaeab2db0a2482676f64798d8ac4d2dbb457523f50ab37bf02ce2c/watchdog-5.0.3.tar.gz", hash = "sha256:108f42a7f0345042a854d4d0ad0834b741d421330d5f575b81cb27b883500176", size = 129556 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/2b/dd2081aab6fc9e785c2eee7146d3c6de58e607f4e70049d715cd170cbf77/watchdog-5.0.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:85527b882f3facda0579bce9d743ff7f10c3e1e0db0a0d0e28170a7d0e5ce2ea", size = 96652 }, + { url = "https://files.pythonhosted.org/packages/9e/4f/f643c0a720d16ef7316aea06a79b96e229e59df4e0d83bec5e12713c1f29/watchdog-5.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:53adf73dcdc0ef04f7735066b4a57a4cd3e49ef135daae41d77395f0b5b692cb", size = 88651 }, + { url = "https://files.pythonhosted.org/packages/2b/72/acb22067d1f18161914c9b1087c703d63638131a9fde78090da290663407/watchdog-5.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e25adddab85f674acac303cf1f5835951345a56c5f7f582987d266679979c75b", size = 89289 }, + { url = "https://files.pythonhosted.org/packages/70/34/946f08602f8b8e6af45bc725e4a8013975a34883ab5570bd0d827a4c9829/watchdog-5.0.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f01f4a3565a387080dc49bdd1fefe4ecc77f894991b88ef927edbfa45eb10818", size = 96650 }, + { url = "https://files.pythonhosted.org/packages/96/2b/b84e35d49e8b0bad77e5d086fc1e2c6c833bbfe74d53144cfe8b26117eff/watchdog-5.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:91b522adc25614cdeaf91f7897800b82c13b4b8ac68a42ca959f992f6990c490", size = 88653 }, + { url = "https://files.pythonhosted.org/packages/d5/3f/41b5d77c10f450b79921c17b7d0b416616048867bfe63acaa072a619a0cb/watchdog-5.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d52db5beb5e476e6853da2e2d24dbbbed6797b449c8bf7ea118a4ee0d2c9040e", size = 89286 }, + { url = "https://files.pythonhosted.org/packages/1c/9b/8b206a928c188fdeb7b12e1c795199534cd44bdef223b8470129016009dd/watchdog-5.0.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:94d11b07c64f63f49876e0ab8042ae034674c8653bfcdaa8c4b32e71cfff87e8", size = 96739 }, + { url = "https://files.pythonhosted.org/packages/e1/26/129ca9cd0f8016672f37000010c2fedc0b86816e894ebdc0af9bb04a6439/watchdog-5.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:349c9488e1d85d0a58e8cb14222d2c51cbc801ce11ac3936ab4c3af986536926", size = 88708 }, + { url = "https://files.pythonhosted.org/packages/8f/b3/5e10ec32f0c429cdb55b1369066d6e83faf9985b3a53a4e37bb5c5e29aa0/watchdog-5.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:53a3f10b62c2d569e260f96e8d966463dec1a50fa4f1b22aec69e3f91025060e", size = 89309 }, + { url = "https://files.pythonhosted.org/packages/54/c4/49af4ab00bcfb688e9962eace2edda07a2cf89b9699ea536da48e8585cff/watchdog-5.0.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:950f531ec6e03696a2414b6308f5c6ff9dab7821a768c9d5788b1314e9a46ca7", size = 96740 }, + { url = "https://files.pythonhosted.org/packages/96/a4/b24de77cc9ae424c1687c9d4fb15aa560d7d7b28ba559aca72f781d0202b/watchdog-5.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ae6deb336cba5d71476caa029ceb6e88047fc1dc74b62b7c4012639c0b563906", size = 88711 }, + { url = "https://files.pythonhosted.org/packages/a4/71/3f2e9fe8403386b99d788868955b3a790f7a09721501a7e1eb58f514ffaa/watchdog-5.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1021223c08ba8d2d38d71ec1704496471ffd7be42cfb26b87cd5059323a389a1", size = 89319 }, + { url = "https://files.pythonhosted.org/packages/51/84/fc0b390012be6c4884d02bbef28d599afc6eeec4b560820bec98ff156fd1/watchdog-5.0.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:752fb40efc7cc8d88ebc332b8f4bcbe2b5cc7e881bccfeb8e25054c00c994ee3", size = 96649 }, + { url = "https://files.pythonhosted.org/packages/e7/c5/5393fd01610a92bb7b291b742daae8d1b89f8e11bfb2c37361e17e1be1b8/watchdog-5.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a2e8f3f955d68471fa37b0e3add18500790d129cc7efe89971b8a4cc6fdeb0b2", size = 88647 }, + { url = "https://files.pythonhosted.org/packages/95/27/1eef63ba7015132a971e0304675497783faaf1ccb4f8223b06b9dfd90ba0/watchdog-5.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b8ca4d854adcf480bdfd80f46fdd6fb49f91dd020ae11c89b3a79e19454ec627", size = 89285 }, + { url = "https://files.pythonhosted.org/packages/a2/d6/1d1ca81c75d903eca3fdb7061d93845485b58a5ba182d146843b88fc51c2/watchdog-5.0.3-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:90a67d7857adb1d985aca232cc9905dd5bc4803ed85cfcdcfcf707e52049eda7", size = 88172 }, + { url = "https://files.pythonhosted.org/packages/47/bb/d5e0abcfd6d729029a24766682e062526db8b59e9ae0c94aff509e0fd2b9/watchdog-5.0.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:720ef9d3a4f9ca575a780af283c8fd3a0674b307651c1976714745090da5a9e8", size = 88644 }, + { url = "https://files.pythonhosted.org/packages/8e/f6/0b9daa3398c3e2918fe79666540eedcbdc07614e77b2154cb35928d0c757/watchdog-5.0.3-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:223160bb359281bb8e31c8f1068bf71a6b16a8ad3d9524ca6f523ac666bb6a1e", size = 88173 }, + { url = "https://files.pythonhosted.org/packages/27/c5/ce5bb0ce5587ce0899693be9fe20041e301fec143aae54066ac616a925b4/watchdog-5.0.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:560135542c91eaa74247a2e8430cf83c4342b29e8ad4f520ae14f0c8a19cfb5b", size = 88647 }, + { url = "https://files.pythonhosted.org/packages/60/33/7cb71c9df9a77b6927ee5f48d25e1de5562ce0fa7e0c56dcf2b0472e64a2/watchdog-5.0.3-py3-none-manylinux2014_aarch64.whl", hash = "sha256:dd021efa85970bd4824acacbb922066159d0f9e546389a4743d56919b6758b91", size = 79335 }, + { url = "https://files.pythonhosted.org/packages/f6/91/320bc1496cf951a3cf93a7ffd18a581f0792c304be963d943e0e608c2919/watchdog-5.0.3-py3-none-manylinux2014_armv7l.whl", hash = "sha256:78864cc8f23dbee55be34cc1494632a7ba30263951b5b2e8fc8286b95845f82c", size = 79334 }, + { url = "https://files.pythonhosted.org/packages/8b/2c/567c5e042ed667d3544c43d48a65cf853450a2d2a9089d9523a65f195e94/watchdog-5.0.3-py3-none-manylinux2014_i686.whl", hash = "sha256:1e9679245e3ea6498494b3028b90c7b25dbb2abe65c7d07423ecfc2d6218ff7c", size = 79333 }, + { url = "https://files.pythonhosted.org/packages/c3/f0/64059fe162ef3274662e67bbdea6c45b3cd53e846d5bd1365fcdc3dc1d15/watchdog-5.0.3-py3-none-manylinux2014_ppc64.whl", hash = "sha256:9413384f26b5d050b6978e6fcd0c1e7f0539be7a4f1a885061473c5deaa57221", size = 79334 }, + { url = "https://files.pythonhosted.org/packages/f6/d9/19b7d02965be2801e2d0f6f4bde23e4ae172620071b65430fa0c2f8441ac/watchdog-5.0.3-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:294b7a598974b8e2c6123d19ef15de9abcd282b0fbbdbc4d23dfa812959a9e05", size = 79333 }, + { url = "https://files.pythonhosted.org/packages/cb/a1/5393ac6d0b095d3a44946b09258e9b5f22cb2fb67bcfa419dd868478826c/watchdog-5.0.3-py3-none-manylinux2014_s390x.whl", hash = "sha256:26dd201857d702bdf9d78c273cafcab5871dd29343748524695cecffa44a8d97", size = 79332 }, + { url = "https://files.pythonhosted.org/packages/a0/58/edec25190b6403caf4426dd418234f2358a106634b7d6aa4aec6939b104f/watchdog-5.0.3-py3-none-manylinux2014_x86_64.whl", hash = "sha256:0f9332243355643d567697c3e3fa07330a1d1abf981611654a1f2bf2175612b7", size = 79334 }, + { url = "https://files.pythonhosted.org/packages/97/69/cfb2d17ba8aabc73be2e2d03c8c319b1f32053a02c4b571852983aa24ff2/watchdog-5.0.3-py3-none-win32.whl", hash = "sha256:c66f80ee5b602a9c7ab66e3c9f36026590a0902db3aea414d59a2f55188c1f49", size = 79320 }, + { url = "https://files.pythonhosted.org/packages/91/b4/2b5b59358dadfa2c8676322f955b6c22cde4937602f40490e2f7403e548e/watchdog-5.0.3-py3-none-win_amd64.whl", hash = "sha256:f00b4cf737f568be9665563347a910f8bdc76f88c2970121c86243c8cfdf90e9", size = 79325 }, + { url = "https://files.pythonhosted.org/packages/38/b8/0aa69337651b3005f161f7f494e59188a1d8d94171666900d26d29d10f69/watchdog-5.0.3-py3-none-win_ia64.whl", hash = "sha256:49f4d36cb315c25ea0d946e018c01bb028048023b9e103d3d3943f58e109dd45", size = 79324 }, ] [[package]] From f8bc63089e48b609921080edaa717423efb48a02 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 14:06:43 +0000 Subject: [PATCH 32/43] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/dcspy/qt_gui.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dcspy/qt_gui.py b/src/dcspy/qt_gui.py index bfad44a3e..18ebeb2dd 100644 --- a/src/dcspy/qt_gui.py +++ b/src/dcspy/qt_gui.py @@ -20,7 +20,7 @@ from packaging import version from pydantic_core import ValidationError from PySide6 import __version__ as pyside6_ver -from PySide6.QtCore import QAbstractItemModel, QEvent, QFile, QIODevice, QMetaObject, QObject, QRunnable, Qt, QThreadPool, Signal, SignalInstance, Slot, qVersion +from PySide6.QtCore import QAbstractItemModel, QEvent, QFile, QIODevice, QMetaObject, QRunnable, Qt, QThreadPool, Signal, Slot, qVersion from PySide6.QtGui import QAction, QActionGroup, QBrush, QFont, QIcon, QPainter, QPen, QPixmap, QShowEvent, QStandardItemModel from PySide6.QtUiTools import QUiLoader from PySide6.QtWidgets import (QApplication, QButtonGroup, QCheckBox, QComboBox, QCompleter, QDialog, QDockWidget, QFileDialog, QGroupBox, QLabel, QLineEdit, @@ -32,8 +32,8 @@ GuiPlaneInputRequest, LcdButton, LcdMono, LcdType, LogitechDeviceModel, MouseButton, MsgBoxTypes, ReleaseInfo, RequestType, SystemData) from dcspy.starter import dcspy_run -from dcspy.utils import (CloneProgress, SignalHandler, check_bios_ver, check_dcs_bios_entry, check_dcs_ver, check_github_repo, check_ver_at_github, collect_debug_data, - count_files, defaults_cfg, download_file, generate_bios_jsons_with_lupa, get_all_git_refs, get_depiction_of_ctrls, +from dcspy.utils import (CloneProgress, SignalHandler, check_bios_ver, check_dcs_bios_entry, check_dcs_ver, check_github_repo, check_ver_at_github, + collect_debug_data, count_files, defaults_cfg, download_file, generate_bios_jsons_with_lupa, get_all_git_refs, get_depiction_of_ctrls, get_inputs_for_plane, get_list_of_ctrls, get_plane_aliases, get_planes_list, get_version_string, is_git_exec_present, is_git_object, load_yaml, proc_is_running, run_command, run_pip_command, save_yaml) From 4138d01e116007457fe0bea9cc84ea8f676acc40 Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Mon, 4 Nov 2024 15:09:54 +0100 Subject: [PATCH 33/43] fix typing in dcsbios --- src/dcspy/dcsbios.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dcspy/dcsbios.py b/src/dcspy/dcsbios.py index 30d08d176..e027a4836 100644 --- a/src/dcspy/dcsbios.py +++ b/src/dcspy/dcsbios.py @@ -127,7 +127,7 @@ def _wait_for_sync(self) -> None: class StringBuffer: """String buffer for DCS-BIOS protocol.""" - def __init__(self, parser: ProtocolParser, address: int, max_length: int, callback: Callable, sig_handler: Optional[SignalHandler] = None) -> None: + def __init__(self, parser: ProtocolParser, address: int, max_length: int, callback: Callable, sig_handler: SignalHandler | None = None) -> None: """ Initialize instance. @@ -189,7 +189,7 @@ def check_callbacks(self, str_buff: str) -> None: class IntegerBuffer: """Integer buffer for DCS-BIOS protocol.""" - def __init__(self, parser: ProtocolParser, address: int, mask: int, shift_by: int, callback: Callable, sig_handler: Optional[SignalHandler] = None) -> None: + def __init__(self, parser: ProtocolParser, address: int, mask: int, shift_by: int, callback: Callable, sig_handler: SignalHandler | None = None) -> None: """ Initialize instance. From e3aa9b5582a592aaa9dbe5c02c57f78de6755ebe Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Mon, 4 Nov 2024 19:24:06 +0100 Subject: [PATCH 34/43] use new type annotations in logitech module --- src/dcspy/logitech.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/dcspy/logitech.py b/src/dcspy/logitech.py index d440334b9..471573af1 100644 --- a/src/dcspy/logitech.py +++ b/src/dcspy/logitech.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from functools import partial from importlib import import_module from logging import getLogger @@ -5,7 +7,6 @@ from pprint import pformat from socket import socket from time import sleep -from typing import Optional from PIL import Image, ImageDraw @@ -21,7 +22,7 @@ class LogitechDevice: """General Logitech device.""" - def __init__(self, parser: dcsbios.ProtocolParser, sock: socket, model: LogitechDeviceModel, sig_handler: Optional[SignalHandler] = None) -> None: + def __init__(self, parser: dcsbios.ProtocolParser, sock: socket, model: LogitechDeviceModel, sig_handler: SignalHandler | None = None) -> None: """ General Logitech device. From 27bb0cfb901f7bcca12b5df18ed62119136dfc4c Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Thu, 7 Nov 2024 18:59:21 +0100 Subject: [PATCH 35/43] organize imports --- src/dcspy/qt_gui.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dcspy/qt_gui.py b/src/dcspy/qt_gui.py index 7b2981a48..7075d0f1a 100644 --- a/src/dcspy/qt_gui.py +++ b/src/dcspy/qt_gui.py @@ -32,8 +32,8 @@ FontsConfig, Gkey, GuiPlaneInputRequest, LcdButton, LcdMono, LcdType, LogitechDeviceModel, MouseButton, MsgBoxTypes, ReleaseInfo, RequestType, SystemData) from dcspy.starter import dcspy_run -from dcspy.utils import (CloneProgress, SignalHandler, check_bios_ver, check_dcs_bios_entry, check_dcs_ver, check_github_repo, check_ver_at_github, collect_debug_data, - count_files, defaults_cfg, download_file, generate_bios_jsons_with_lupa, get_all_git_refs, get_depiction_of_ctrls, +from dcspy.utils import (CloneProgress, SignalHandler, check_bios_ver, check_dcs_bios_entry, check_dcs_ver, check_github_repo, check_ver_at_github, + collect_debug_data, count_files, defaults_cfg, download_file, generate_bios_jsons_with_lupa, get_all_git_refs, get_depiction_of_ctrls, get_inputs_for_plane, get_list_of_ctrls, get_plane_aliases, get_planes_list, get_version_string, is_git_exec_present, is_git_object, load_yaml, proc_is_running, run_command, run_pip_command, save_yaml) From 0725ba9e9b82cb6d766650a6531a76789fabb647 Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Thu, 7 Nov 2024 20:13:56 +0100 Subject: [PATCH 36/43] update mkdocs-material (cherry picked from commit 9abab3b60f532edb6dc7914200f1cbd9379a4bad) --- docs/requirements.txt | 2 +- pyproject.toml | 2 +- requirements_docs.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 982723572..a7870ad36 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -2,7 +2,7 @@ black==24.10.0 mkdocs==1.6.1 mkdocs-gen-files==0.5.0 mkdocs-literate-nav==0.6.1 -mkdocs-material==9.5.43 +mkdocs-material==9.5.44 mkdocs-plantuml==0.1.1 mkdocs-section-index==0.3.9 mkdocstrings==0.26.2 diff --git a/pyproject.toml b/pyproject.toml index 2f97a1c3e..ff44b5faa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -92,7 +92,7 @@ docs = [ 'mkdocs==1.6.1', 'mkdocs-gen-files==0.5.0', 'mkdocs-literate-nav==0.6.1', - 'mkdocs-material==9.5.43', + 'mkdocs-material==9.5.44', 'mkdocs-plantuml==0.1.1', 'mkdocs-section-index==0.3.9', 'mkdocstrings==0.26.2', diff --git a/requirements_docs.txt b/requirements_docs.txt index 7d1c26965..43b4b8ff6 100644 --- a/requirements_docs.txt +++ b/requirements_docs.txt @@ -3,7 +3,7 @@ black==24.10.0 mkdocs==1.6.1 mkdocs-gen-files==0.5.0 mkdocs-literate-nav==0.6.1 -mkdocs-material==9.5.43 +mkdocs-material==9.5.44 mkdocs-plantuml==0.1.1 mkdocs-section-index==0.3.9 mkdocstrings==0.26.2 From ba1f26b868a1f86ba8e71eda16cd706493eb5220 Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Mon, 8 Sep 2025 10:29:11 +0200 Subject: [PATCH 37/43] fix one minor issue --- src/dcspy/qt_gui.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dcspy/qt_gui.py b/src/dcspy/qt_gui.py index 7075d0f1a..11875be14 100644 --- a/src/dcspy/qt_gui.py +++ b/src/dcspy/qt_gui.py @@ -50,13 +50,13 @@ class CircleLabel(QLabel): """Blinking green circle.""" - def __init__(self, color_on: Qt.GlobalColor = Qt.GlobalColor.green, *args, **kwargs) -> None: + def __init__(self, color_on: Qt.GlobalColor = Qt.GlobalColor.green, **kwargs) -> None: """ Initialize the object with the given parameters. :param color_on: The color when the label is in `on` state, default is green. """ - super().__init__(*args, **kwargs) + super().__init__(**kwargs) self.state = False self.pen = QPen(Qt.GlobalColor.black) self.brush_on = QBrush(color_on) From e05ccc0b1eb17c89e814d431fd52b035cc0be408 Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Mon, 8 Sep 2025 14:32:42 +0200 Subject: [PATCH 38/43] update requests --- pyproject.toml | 4 ++-- requirements.txt | 2 +- requirements_test.txt | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 4d0794816..df2ac9ddb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,7 +49,7 @@ dependencies = [ 'pydantic==2.10.5', 'pyside6==6.8.1', 'pyyaml==6.0.2', - 'requests==2.32.3', + 'requests==2.32.5', 'typing-extensions==4.12.2 ; python_full_version < "3.12"', ] @@ -85,7 +85,7 @@ test = [ 'types-psutil==6.1.0.20241221', 'types-pyinstaller==6.11.0.20241028', 'types-pyyaml==6.0.12.20241230', - 'types-requests==2.32.0.20241016', + 'types-requests==2.32.4.20250809', ] docs = [ 'black==24.10.0', diff --git a/requirements.txt b/requirements.txt index 9948b8779..7bb67b308 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,5 +8,5 @@ psutil==6.1.1 pydantic==2.10.5 PySide6==6.8.1 PyYAML==6.0.2 -requests==2.32.3 +requests==2.32.5 typing_extensions==4.12.2; python_version < '3.12' diff --git a/requirements_test.txt b/requirements_test.txt index c366777de..15e11f023 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -17,4 +17,4 @@ types-Pillow==10.2.0.20240822 types-psutil==6.1.0.20241221 types-pyinstaller==6.11.0.20241028 types-PyYAML==6.0.12.20241230 -types-requests==2.32.0.20241016 +types-requests==2.32.4.20250809 From 936b2f8db53670cc22714cb945e517ff6472f07f Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Mon, 8 Sep 2025 14:35:26 +0200 Subject: [PATCH 39/43] update mypy --- .pre-commit-config.yaml | 2 +- pyproject.toml | 2 +- requirements_test.txt | 2 +- src/dcspy/qt_gui.py | 3 +-- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 770364dc0..e3df18285 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -31,7 +31,7 @@ repos: exclude: 'helpers.py' - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.14.1 + rev: v1.17.1 hooks: - id: mypy exclude: '/qt_gui\.py$|/qtgui_rc\.py$|tests/|generate_ver_file\.py$' diff --git a/pyproject.toml b/pyproject.toml index df2ac9ddb..c91770df1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,7 +71,7 @@ test = [ 'interrogate==1.7.0', 'isort==5.13.2', 'lxml==5.3.0', - 'mypy==1.14.1', + 'mypy==1.17.1', 'pip-audit==2.7.3', 'pycodestyle==2.12.1', 'pytest==8.3.4', diff --git a/requirements_test.txt b/requirements_test.txt index 15e11f023..7e5edc856 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -3,7 +3,7 @@ flake8==7.1.1 interrogate==1.7.0 isort==5.13.2 lxml==5.3.0 -mypy==1.14.1 +mypy==1.17.1 pip-audit==2.7.3 pycodestyle==2.12.1 pytest==8.3.4 diff --git a/src/dcspy/qt_gui.py b/src/dcspy/qt_gui.py index da531e5dc..5f8397e62 100644 --- a/src/dcspy/qt_gui.py +++ b/src/dcspy/qt_gui.py @@ -15,13 +15,12 @@ from tempfile import gettempdir from threading import Event from time import sleep -from typing import Any from webbrowser import open_new_tab from packaging import version from pydantic_core import ValidationError from PySide6 import __version__ as pyside6_ver -from PySide6.QtCore import QAbstractItemModel, QEvent, QFile, QIODevice, QMetaObject, QObject, QRunnable, Qt, QThreadPool, Signal, SignalInstance, Slot, qVersion +from PySide6.QtCore import QAbstractItemModel, QEvent, QFile, QIODevice, QMetaObject, QRunnable, Qt, QThreadPool, Signal, Slot, qVersion from PySide6.QtGui import QAction, QActionGroup, QBrush, QFont, QIcon, QPainter, QPen, QPixmap, QShowEvent, QStandardItemModel from PySide6.QtUiTools import QUiLoader from PySide6.QtWidgets import (QApplication, QButtonGroup, QCheckBox, QComboBox, QCompleter, QDialog, QDockWidget, QFileDialog, QGroupBox, QLabel, QLineEdit, From eabbb58d4758caaabd9e068a386ec946f1a68df2 Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Mon, 8 Sep 2025 14:36:50 +0200 Subject: [PATCH 40/43] remove thread --- src/dcspy/qt_gui.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/dcspy/qt_gui.py b/src/dcspy/qt_gui.py index 5f8397e62..adaeb90cc 100644 --- a/src/dcspy/qt_gui.py +++ b/src/dcspy/qt_gui.py @@ -1328,10 +1328,6 @@ def _start_clicked(self) -> None: fonts_cfg = FontsConfig(name=self.le_font_name.text(), **getattr(self, f'{self.device.lcd_name}_font')) self.device.lcd_info.set_fonts(fonts_cfg) self.event = Event() - app_params = {'model': self.device, 'event': self.event} - app_thread = Thread(target=dcspy_run, kwargs=app_params) - app_thread.name = 'dcspy-app' - LOG.debug(f'Starting thread {app_thread} for: {app_params}') self.pb_start.setEnabled(False) self.a_start.setEnabled(False) self.pb_stop.setEnabled(True) From 266dc0dd0ef1d70d1ba46cbe9b3f4a5c49348a8f Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Mon, 8 Sep 2025 14:38:24 +0200 Subject: [PATCH 41/43] fix mypy --- src/dcspy/__init__.py | 2 +- src/dcspy/logitech.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dcspy/__init__.py b/src/dcspy/__init__.py index 158411d50..9147f11b0 100644 --- a/src/dcspy/__init__.py +++ b/src/dcspy/__init__.py @@ -38,4 +38,4 @@ def get_config_yaml_item(key: str, /, default: ConfigValue | None = None) -> Con :param default: Default value if key not found :return: Value from configuration """ - return load_yaml(full_path=default_yaml).get(key, default) + return load_yaml(full_path=default_yaml).get(key, default) # type: ignore[return-value] diff --git a/src/dcspy/logitech.py b/src/dcspy/logitech.py index 9dfca1778..30fe579bd 100644 --- a/src/dcspy/logitech.py +++ b/src/dcspy/logitech.py @@ -154,7 +154,7 @@ def _setup_plane_callback(self) -> None: ctrl = plane_bios.get_ctrl(ctrl_name=ctrl_name) dcsbios_buffer = getattr(dcsbios, ctrl.output.klass) # type: ignore[union-attr] dcsbios_buffer(parser=self.parser, callback=partial(self.plane.set_bios, ctrl_name), - sig_handler=self.sig_handler, **ctrl.output.args.model_dump()) + sig_handler=self.sig_handler, **ctrl.output.args.model_dump()) # type: ignore[union-attr] def gkey_callback_handler(self, key_idx: int, mode: int, key_down: int, mouse: int) -> None: """ From c860f5e02a80351a0c386d289113c465567059dc Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Mon, 8 Sep 2025 14:43:08 +0200 Subject: [PATCH 42/43] add from __future__ import annotations --- src/dcspy/logitech.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/dcspy/logitech.py b/src/dcspy/logitech.py index 30fe579bd..e00f0b22c 100644 --- a/src/dcspy/logitech.py +++ b/src/dcspy/logitech.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from copy import copy from functools import partial from importlib import import_module From 0e141dc2fdf90a65e057e1103bd0ebbf75052d54 Mon Sep 17 00:00:00 2001 From: Michal Plichta Date: Mon, 8 Sep 2025 14:50:37 +0200 Subject: [PATCH 43/43] some updates form master --- .github/workflows/license.yml | 7 ++++--- .github/workflows/style.yml | 32 +++----------------------------- .pre-commit-config.yaml | 6 ------ mkdocs.yml | 4 +--- 4 files changed, 8 insertions(+), 41 deletions(-) diff --git a/.github/workflows/license.yml b/.github/workflows/license.yml index a668af7bb..c39f2e8f1 100644 --- a/.github/workflows/license.yml +++ b/.github/workflows/license.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest steps: - name: "Checkout" - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: "Set up Python 3.13" uses: actions/setup-python@v5 @@ -26,12 +26,13 @@ jobs: - name: "Check License" id: license_check_report - uses: pilosus/action-pip-license-checker@v2 + uses: pilosus/action-pip-license-checker@v3 with: requirements: 'requirements-all.txt' - fail: 'StrongCopyleft,Other,Error' + fail: 'StrongCopyleft,Error' totals: true headers: true + exclude: '(?i)^(pyside6|shiboken6).*' - name: "Print report" if: ${{ always() }} diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml index f96b76778..fccac5df2 100644 --- a/.github/workflows/style.yml +++ b/.github/workflows/style.yml @@ -3,24 +3,11 @@ name: Style on: workflow_call jobs: - pycodestyle: - runs-on: ubuntu-latest - steps: - - name: "Checkout" - uses: actions/checkout@v4 - - - name: "Set up Python environment" - uses: ./.github/actions/setup-python - - - name: "Check PyCodeStyle" - run: | - pycodestyle --statistics --count src - interrogate: runs-on: ubuntu-latest steps: - name: "Checkout" - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: "Set up Python environment" uses: ./.github/actions/setup-python @@ -33,7 +20,7 @@ jobs: runs-on: ubuntu-latest steps: - name: "Checkout" - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: "Set up Python environment" uses: ./.github/actions/setup-python @@ -46,7 +33,7 @@ jobs: runs-on: ubuntu-latest steps: - name: "Checkout" - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: "Set up Python environment" uses: ./.github/actions/setup-python @@ -63,16 +50,3 @@ jobs: path: | mypyhtml/* retention-days: 4 - - flake8: - runs-on: ubuntu-latest - steps: - - name: "Checkout" - uses: actions/checkout@v4 - - - name: "Set up Python environment" - uses: ./.github/actions/setup-python - - - name: "Check flake8" - run: | - flake8 src diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e3df18285..759f65861 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -44,12 +44,6 @@ repos: exclude: '/qtgui_rc.py$|tests/' args: [--fix, --exit-non-zero-on-fix] - - repo: https://github.com/PyCQA/flake8 - rev: 7.1.1 - hooks: - - id: flake8 - exclude: '/qtgui_rc.py$|tests/' - - repo: https://github.com/asottile/pyupgrade rev: v3.19.1 hooks: diff --git a/mkdocs.yml b/mkdocs.yml index 12eed6974..16028ac4b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -2,7 +2,7 @@ site_name: DCSpy site_url: https://dcspy.readthedocs.io/ site_description: Software for integrating DCS Planes with Logitech keyboards (with and without LCD), mice and headphones. repo_url: https://github.com/emcek/dcspy -copyright: Copyright © 2019 Michał Plichta +copyright: Copyright © 2019-2025 Michał Plichta theme: name: material @@ -75,8 +75,6 @@ plugins: - https://docs.python.org/3/objects.inv paths: [ src ] options: - docstring_options: - ignore_init_summary: true docstring_section_style: table docstring_style: sphinx filters: [ "!^_" ]