Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
84b5e4e
Update CHANGELOG with v3.5.2 details
emcek Jul 6, 2024
fa1b314
Merge branch 'refs/heads/master' into client_in_qthread
emcek Jul 13, 2024
dc6000e
Add Qt signal handling to utils module as SignalHandler
emcek Jul 14, 2024
06b1f99
Refactor signal handling in GitProgressHandler
emcek Jul 14, 2024
5f53e1e
Refactor signal handling in GitProgressHandler
emcek Jul 14, 2024
2251fbc
Refactor clone test to use SignalHandler
emcek Jul 14, 2024
aaebe65
Add optional SignalHandler to StringBuffer and IntegerBuffer classes
emcek Jul 14, 2024
1d417d9
Add SignalHandler to LogitechDevice class
emcek Jul 14, 2024
f070441
Add SignalHandler to dcspy_run and _handle_connection functions in st…
emcek Jul 14, 2024
39b122e
Refactor code for better error handling and status reporting
emcek Jul 14, 2024
faf370b
Refactor callback handling into separate methods
emcek Jul 14, 2024
fb79e25
Add SignalHandler class and integrate into existing classes
emcek Jul 14, 2024
7765ff4
Update docstrings in SignalHandler class
emcek Jul 14, 2024
63d5e5d
Reformat _handle_connection function
emcek Jul 14, 2024
674266e
Update method documentation in qt_gui.py
emcek Jul 14, 2024
0fdf5f7
Refine error message in custom message box during bios update
emcek Jul 14, 2024
5587485
Update clone progress in test_utils
emcek Jul 14, 2024
a32e42e
Skip test_clone_progress in test_utils
emcek Jul 14, 2024
2430ed9
Remove skip mark from clone progress test
emcek Jul 14, 2024
89a5147
Comment out mouse clicks (start, stop) in qtgui tests
emcek Jul 15, 2024
ba548ee
Enable start and stop button clicks in qtgui test with sleep
emcek Jul 15, 2024
1831708
revert changes in qt test
emcek Jul 15, 2024
5e72e3b
deselect qt6 tests
emcek Jul 15, 2024
c3147b4
Merge branch 'refs/heads/master' into client_in_qthread
emcek Jul 22, 2024
7b1f8e6
A new CircleLabel class was added to qt_gui.py to create a circular l…
emcek Jul 22, 2024
d731f66
Add statusbar initialization and update statusbar calls
emcek Jul 22, 2024
78b6134
Fix ruff and docstring
emcek Jul 22, 2024
6707745
Update byte display with unit in status label
emcek Jul 22, 2024
d91fe92
Update types-PyYAML in requirements_test.txt
emcek Jul 24, 2024
5b735d3
Merge branch 'refs/heads/master' into client_in_qthread
emcek Aug 3, 2024
ee3be48
Merge branch 'refs/heads/master' into client_in_qthread
emcek Aug 6, 2024
e7174bf
Update package versions in dependencies
emcek Aug 11, 2024
869b759
Merge branch 'master' into client_in_qthread
emcek Aug 30, 2024
ecde9c3
optimize imports
emcek Aug 30, 2024
77f431d
Merge branch 'master' into client_in_qthread
emcek Sep 3, 2024
d201a56
Merge remote-tracking branch 'origin/master' into client_in_qthread
emcek Sep 29, 2024
86ff24d
update docstring
emcek Sep 29, 2024
2500ac8
update lock file
emcek Sep 29, 2024
ca42815
Merge branch 'master' into client_in_qthread
emcek Nov 4, 2024
f8bc630
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 4, 2024
4138d01
fix typing in dcsbios
emcek Nov 4, 2024
e3aa9b5
use new type annotations in logitech module
emcek Nov 4, 2024
3570c3a
Merge branch 'master' into client_in_qthread
emcek Nov 5, 2024
c01ebc4
Merge branch 'master' into client_in_qthread
emcek Nov 7, 2024
27bb0cf
organize imports
emcek Nov 7, 2024
0725ba9
update mkdocs-material
emcek Nov 7, 2024
ba1f26b
fix one minor issue
emcek Sep 8, 2025
a48d2df
Merge branch 'tbd' into client_in_qthread
emcek Sep 8, 2025
e05ccc0
update requests
emcek Sep 8, 2025
936b2f8
update mypy
emcek Sep 8, 2025
eabbb58
remove thread
emcek Sep 8, 2025
266dc0d
fix mypy
emcek Sep 8, 2025
c860f5e
add from __future__ import annotations
emcek Sep 8, 2025
0e141dc
some updates form master
emcek Sep 8, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 4 additions & 3 deletions .github/workflows/license.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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() }}
Expand Down
32 changes: 3 additions & 29 deletions .github/workflows/style.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,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
Expand Down
8 changes: 1 addition & 7 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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$'
Expand All @@ -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:
Expand Down
4 changes: 1 addition & 3 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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: [ "!^_" ]
Expand Down
6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"',
]

Expand All @@ -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',
Expand All @@ -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',
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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'
4 changes: 2 additions & 2 deletions requirements_test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
2 changes: 1 addition & 1 deletion src/dcspy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]
38 changes: 32 additions & 6 deletions src/dcspy/dcsbios.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
from functools import partial
from struct import pack

from dcspy.utils import SignalHandler


class ParserState(Enum):
"""Protocol parser states."""
Expand Down Expand Up @@ -125,21 +127,23 @@ 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: SignalHandler | None = None) -> None:
"""
Initialize instance.

:param parser:
:param address:
:param max_length:
:param callback:
:param sig_handler: Qt signal handler for progress notification
"""
self.__address = address
self.__length = max_length
self.__dirty = False
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:
Expand Down Expand Up @@ -169,13 +173,23 @@ 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)
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:
"""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: SignalHandler | None = None) -> None:
"""
Initialize instance.

Expand All @@ -184,13 +198,15 @@ 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
self.__shift_by = shift_by
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:
Expand All @@ -204,5 +220,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)
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))
10 changes: 7 additions & 3 deletions src/dcspy/logitech.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

from copy import copy
from functools import partial
from importlib import import_module
Expand All @@ -14,15 +16,15 @@
from dcspy.models import (KEY_DOWN, SEND_ADDR, SUPPORTED_CRAFTS, TIME_BETWEEN_REQUESTS, AnyButton, Color, 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, rgba
from dcspy.utils import SignalHandler, get_full_bios_for_plane, get_planes_list, rgba

LOG = getLogger(__name__)


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: SignalHandler | None = None) -> None:
"""
General Logitech device.

Expand All @@ -44,6 +46,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

def text(self, message: list[tuple[str, Color]]) -> None:
"""
Expand Down Expand Up @@ -152,7 +155,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:
"""
Expand Down
Loading
Loading