Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 4 additions & 3 deletions .github/workflows/python-pytest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@ jobs:
run: |
python -m pip install --upgrade pip
pip install -e .
pip install pytest matplotlib
pip install pytest matplotlib pylint
- name: Pytest run
run: |
pytest


- name: PyLint pass
run: |
pylint src/**/*.py
17 changes: 17 additions & 0 deletions .pylintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[MESSAGES CONTROL]
disable=
missing-module-docstring,
missing-function-docstring,
missing-class-docstring,
c-extension-no-member,
no-member,
invalid-name,
too-few-public-methods,
fixme # Remove this someday and fix every TODO

[FORMAT]
max-line-length=121

[DEPRECATED_BUILTINS]
bad-functions=print
load-plugins=pylint.extensions.bad_builtin
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "EpomakerController"
version = "0.0.8"
version = "0.0.9"
description = "Epomakercontroller"
authors = ["Sam Rodgers <samueltrodgers@duck.com>"]
license = "MIT"
Expand Down
6 changes: 3 additions & 3 deletions src/epomakercontroller/cli.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# src/epomakercontroller/cli.py
"""Simple CLI for the EpomakerController package."""

import click
import tkinter as tk
from functools import wraps

import click

from .commands.data.constants import Profile
from .configs.configs import load_main_config
from .epomakercontroller import EpomakerController
Expand Down Expand Up @@ -36,7 +37,6 @@ def wrapper(*args, **kwargs):
@click.version_option(retrieve_app_version(), prog_name="EpomakerController")
def cli() -> None:
"""A simple CLI for the EpomakerController."""
pass


@cli.command()
Expand Down Expand Up @@ -235,7 +235,7 @@ def show_keymap(keymap_filter: str | None) -> None:
to_show = [item for item in data if keymap_filter.lower() in item["name"].lower()]

for item in to_show:
print(f"{item['name']}: {item['value']}")
Logger.log_info(f"{item['name']}: {item['value']}")


if __name__ == "__main__":
Expand Down
8 changes: 3 additions & 5 deletions src/epomakercontroller/commands/EpomakerCommand.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

import dataclasses
from typing import Iterator
from .reports.Report import Report, ReportCollection
import numpy as np
import numpy.typing as npt

from .reports.Report import Report, ReportCollection
from ..logger.logger import Logger


Expand Down Expand Up @@ -106,8 +106,7 @@ def __iter__(self) -> Iterator[Report]:
Yields:
Iterator[Report]: The reports in the command.
"""
for report in self.reports:
yield report
yield from self.reports

def __getitem__(self, key: int) -> Report:
"""Gets a report by index.
Expand All @@ -127,5 +126,4 @@ def iter_report_bytes(self) -> Iterator[bytes]:
Yields:
Iterator[bytes]: The report bytes.
"""
for report_bytes in self.reports.iter_report_bytes():
yield report_bytes
yield from self.reports.iter_report_bytes()
9 changes: 5 additions & 4 deletions src/epomakercontroller/commands/EpomakerImageCommand.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ def _decode_rgb565(pixel: int) -> tuple[int, int, int]:

return r, g, b

# TODO: fix this pylint warning, mova some functionality to separate methods
# pylint: disable=too-many-locals
def encode_image(self, image_path: str) -> None:
"""Encode an image to 16-bit RGB565.

Expand Down Expand Up @@ -90,6 +92,7 @@ def encode_image(self, image_path: str) -> None:
for x in range(image.shape[1]):
r, g, b = image[y, x]
image_16bit[y, x] = self._encode_rgb565(r, g, b)
# pylint: disable=broad-exception-caught
except Exception as e:
Logger.log_error(f"Exception while converting image: {e}")
return
Expand Down Expand Up @@ -146,11 +149,9 @@ def encode_image(self, image_path: str) -> None:
data_buff_pointer : data_buff_pointer + data_buff_length
].tobytes()
)
# Need some padding at the end of the image data
footer_report._pad()
self._insert_report(footer_report)

self.report_footer_prepared = True
self._insert_report(footer_report)
self.report_footer_prepared = footer_report.prepared

if len(self.reports) != len(self.structure):
Logger.log_error(f"Expected {len(self.structure)} reports, got {len(self.reports)}.")
14 changes: 8 additions & 6 deletions src/epomakercontroller/commands/EpomakerKeyRGBCommand.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ def overlay(

class EpomakerKeyRGBCommand(EpomakerCommand):
"""Change a selection of keys to specific RGB values."""

# TODO: Move some logic to separate method to fix the following pylint warning
# pylint: disable=too-many-locals
def __init__(self, frames: list[KeyboardRGBFrame]) -> None:
"""Initializes the EpomakerKeyRGBCommand with a list of frames.

Expand Down Expand Up @@ -151,9 +152,10 @@ def report_data_contain_index(self, report: ReportWithData, index: int) -> bool:
"""
report_index_count = 0
data_buffer_length = BUFF_LENGTH - self.report_data_header_length
for report in self.get_data_reports():
report_data = report[self.report_data_header_length :]
if report_index_count <= index < (report_index_count + data_buffer_length):
return True
report_index_count += len(report_data)

report_data = report[self.report_data_header_length :]
if report_index_count <= index < (report_index_count + data_buffer_length):
return True
report_index_count += len(report_data)

return False
2 changes: 0 additions & 2 deletions src/epomakercontroller/commands/EpomakerTimeCommand.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ def _format_time(time: datetime) -> str:
Returns:
str: The formatted command string.
"""
print("Using:", time)

# Example of formatting for a specific date and time format
# Adjust the formatting based on your specific requirements
year = time.year
Expand Down
16 changes: 6 additions & 10 deletions src/epomakercontroller/commands/reports/Report.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class Report:

def __post_init__(self) -> None:
"""Initializes the report after the dataclass is created."""
if self.header_format_values == {}:
if not self.header_format_values:
self.report_bytearray = bytearray.fromhex(self.header_format_string)
else:
self.report_bytearray = bytearray.fromhex(
Expand Down Expand Up @@ -133,8 +133,7 @@ def __iter__(self) -> Iterator[Report]:
Yields:
Iterator[Report]: The reports in the collection.
"""
for report in self.reports:
yield report
yield from self.reports

def __getitem__(self, key: int) -> Report:
"""Gets a report by index.
Expand All @@ -155,21 +154,18 @@ def __len__(self) -> int:
"""
return len(self.reports)

def __setitem__(self, report: Report) -> None:
def __setitem__(self, index: int, report: Report) -> None:
"""Adds a report to the collection.

Args:
report (Report): The report to add.
"""
if report.index in [
if report.index in set(
r.index for r in self.reports
]:
# Ignoring duplicating report, which is not good btw,
# but currently I'm maintaining previous behaviour
# TODO: Review code logic and refactor if needed
):
return

self.reports.append(report)
self.reports.insert(index, report)

def append(self, report: Report) -> None:
"""Appends a report to the collection.
Expand Down
2 changes: 2 additions & 0 deletions src/epomakercontroller/commands/reports/ReportWithData.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
class ReportWithData(Report):
"""Represents a report with additional data."""

# TODO: Fix the following warning -->
# pylint: disable=too-many-arguments, too-many-positional-arguments
def __init__(
self,
header_format_string: str,
Expand Down
6 changes: 4 additions & 2 deletions src/epomakercontroller/controllers/controller.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from __future__ import annotations

import sys
import typing
import signal

Expand Down Expand Up @@ -48,9 +50,9 @@ def _setup_signal_handling(self) -> None:
"""Sets up signal handling to close the HID device on termination."""
signal.signal(signal.SIGINT, self._signal_handler) # Handle Ctrl+C
signal.signal(signal.SIGTERM, self._signal_handler) # Handle termination
signal.signal(signal.SIGQUIT, self._signal_handler)
signal.signal(signal.SIGQUIT, self._signal_handler)

def _signal_handler(self, sig: int, _: Optional[FrameType]) -> None:
"""Handles signals to ensure the HID device is closed."""
self.close_device()
exit(sig) # Pass code to system
sys.exit(sig) # Pass code to system
15 changes: 12 additions & 3 deletions src/epomakercontroller/epomakercontroller.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
import dataclasses
import os
import time
import hid # type: ignore[import-not-found]
import subprocess
import re

from typing import override
from datetime import datetime
from json import dumps

import hid # type: ignore[import-not-found]

from .configs.constants import TMP_FILE_PATH, RULE_FILE_PATH
from .logger.logger import Logger
from .utils.sensors import get_cpu_usage, get_device_temp
Expand Down Expand Up @@ -43,7 +45,12 @@
from typing import Any, Optional


# pylint: disable=R0903
class EpomakerConfig:
"""
Configuration class that stores EpomakerController settings, parsed from config.json
"""

def __init__(self, config_main: Config) -> None:
all_configs = get_all_configs()
self.config_layout = all_configs.get(ConfigType.CONF_LAYOUT)
Expand Down Expand Up @@ -156,6 +163,7 @@ def _find_product_id(self) -> Optional[int]:
int | None: The product ID if found, None otherwise.
"""

# pylint: disable=W0511
# Todo: optimization
for pid in self.config.product_ids:
self.device_list = hid.enumerate(self.config.vendor_id, pid)
Expand Down Expand Up @@ -228,6 +236,7 @@ def print_device_info(self) -> None:
device["vendor_id"] = f"0x{device['vendor_id']:04x}"
device["product_id"] = f"0x{device['product_id']:04x}"

# pylint: disable=bad-builtin
print(
dumps(
devices,
Expand Down Expand Up @@ -315,8 +324,8 @@ def _send_command(self, command: EpomakerCommand.EpomakerCommand) -> None:

try:
self.device.get_product_string()
except: # noqa: E722
raise IOError("Could not communicate with device")
except IOError as e: # noqa: E722
raise IOError("Could not communicate with device") from e

if not command.report_data_prepared:
return
Expand Down
2 changes: 2 additions & 0 deletions src/epomakercontroller/logger/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class LogScope(enum.StrEnum):
class Logger:
@staticmethod
def log(scope: LogScope, message: str):
# TODO: Refactor to logging library w/ custom format + file writing
# pylint: disable=bad-builtin
print(f"{scope.value}: {message}")

@staticmethod
Expand Down
7 changes: 4 additions & 3 deletions src/epomakercontroller/utils/app_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

def retrieve_app_version():
try:
return version("EpomakerController")
return version("EpomakerController")
except PackageNotFoundError:
return "version number not found"


if __name__ == "__main__":
print(retrieve_app_version())
# pylint: disable=W0141
print(retrieve_app_version())
26 changes: 18 additions & 8 deletions src/epomakercontroller/utils/keyboard_gui.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
from __future__ import annotations

import typing

from pathlib import Path
import tkinter as tk
from tkinter.colorchooser import askcolor as askcolour # thats right
from tkinter.colorchooser import askcolor as askcolour # that's right

from .keyboard_keys import KeyboardKey, KeyboardKeys
from ..commands.EpomakerKeyRGBCommand import KeyMap, KeyboardRGBFrame
from typing import Callable, Literal
from ..configs.configs import Config
from ..logger.logger import Logger


if typing.TYPE_CHECKING:
from typing import Callable, Literal


DEFAULT_KEY_WIDTH = 8
DFAULT_KEY_HEIGHT = 4


# pylint: disable=too-many-instance-attributes
class RGBKeyboardGUI:
def __init__(
self,
Expand Down Expand Up @@ -54,15 +64,15 @@ def _handle_customization(self, item: tuple[str, int]) -> bool:
if identifier == "w":
self.key_width = int(DEFAULT_KEY_WIDTH * value)
return True
elif identifier == "h":
if identifier == "h":
self.key_height = int(DFAULT_KEY_HEIGHT * value)
return True
elif identifier == "x":
if identifier == "x":
self.col_offset += int(DEFAULT_KEY_WIDTH * value)
elif identifier == "y":
self.row_offset += int(DFAULT_KEY_HEIGHT * value)
else:
print(f"Warning: Unknown customization identifier: {identifier}")
Logger.log_warning(f"Unknown customization identifier: {identifier}")

return False

Expand Down Expand Up @@ -100,8 +110,8 @@ def noop() -> None:
keyboardkeys_row.append(key)
else:
# We will still display the key but it will show as being disabled.
print(
f"Warning: key from config json with name {col} does not match any KeyboardKey"
Logger.log_warning(
f"key from config json with name {col} does not match any KeyboardKey"
)

# Create the button
Expand Down Expand Up @@ -162,7 +172,7 @@ def apply_colour_to_selected_keys(self, _: object) -> None:
self.frame.overlay(self.selected_key, (r, g, b))
self.callback([self.frame])

print(
Logger.log_info(
f"Set {','.join([k.name for k in self.selected_key])} keys to {colour}"
)
self.selected_key.clear()
Loading