Skip to content

Commit

Permalink
Merge pull request #22 from maresb/types
Browse files Browse the repository at this point in the history
Add some type hints
  • Loading branch information
tomers authored Apr 28, 2024
2 parents 65fcf51 + 6fded70 commit 9a3b9bf
Show file tree
Hide file tree
Showing 21 changed files with 118 additions and 98 deletions.
8 changes: 8 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,16 @@ repos:
hooks:
- id: mypy
additional_dependencies:
- darkdetect
- platformdirs
# This is a hack to get type checking for PyQt6 but to stay under
# pre-commit.ci's 250MiB limit.
# <https://github.com/maresb/pyqt6-without-qt>
- pyqt6-without-qt
- typer
- types-pillow
- types-cffi
- types-pygments

- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.39.0
Expand Down
18 changes: 11 additions & 7 deletions src/labelle/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# === END LICENSE STATEMENT ===
import logging
from pathlib import Path
from typing import List, Optional
from typing import List, NoReturn, Optional

import typer
from rich.console import Console
Expand Down Expand Up @@ -54,15 +54,15 @@
LOG = logging.getLogger(__name__)


def mm_to_payload_px(mm: float, margin: float):
def mm_to_payload_px(mm: float, margin: float) -> float:
"""Convert a length in mm to a number of pixels of payload.
The print resolution is 7 pixels/mm, and margin is subtracted from each side.
"""
return max(0, (mm * PIXELS_PER_MM) - margin * 2)


def version_callback(value: bool):
def version_callback(value: bool) -> None:
if value:
typer.echo(f"Labelle: {__version__}")
raise typer.Exit()
Expand Down Expand Up @@ -92,7 +92,7 @@ def get_device_manager() -> DeviceManager:


@app.command(hidden=True)
def list_devices():
def list_devices() -> NoReturn:
device_manager = get_device_manager()
console = Console()
headers = ["Manufacturer", "Product", "Serial Number", "USB"]
Expand Down Expand Up @@ -123,7 +123,8 @@ def default(
"--device",
help=(
"Select a particular device by filtering for a given substring "
"in the device's manufacturer, product or serial number"
"in the device's manufacturer, product or serial number. Call "
"with 'list' to list all available devices."
),
rich_help_panel="Device Configuration",
),
Expand Down Expand Up @@ -234,14 +235,17 @@ def default(
Optional[int],
typer.Option(help="Tape size [mm]", rich_help_panel="Device Configuration"),
] = None,
):
) -> None:
if ctx.invoked_subcommand is not None:
return

if (not verbose) and (not is_verbose_env_vars()):
# Neither --verbose flag nor the environment variable is set.
set_not_verbose()

if device_pattern == ["list"]:
list_devices()

# read config file
try:
font_path = get_font_path(font=font, style=style)
Expand Down Expand Up @@ -366,7 +370,7 @@ def default(
output_bitmap(bitmap, output)


def main():
def main() -> None:
configure_logging()
app()

Expand Down
2 changes: 1 addition & 1 deletion src/labelle/gui/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
LOG = logging.getLogger(__name__)


def crash_msg_box(parent: QWidget, title: str, err: Exception):
def crash_msg_box(parent: QWidget, title: str, err: Exception) -> None:
print_exception(err)
text = f"{err!r}\n\n{traceback.format_exc() if is_verbose() else VERBOSE_NOTICE}"
QMessageBox.warning(parent, title, text)
22 changes: 11 additions & 11 deletions src/labelle/gui/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class LabelleWindow(QWidget):
_render_context: RenderContext
_render_widget: QWidget

def __init__(self):
def __init__(self) -> None:
super().__init__()
self._label_bitmap_to_print = None
self._detected_device = None
Expand All @@ -55,7 +55,7 @@ def __init__(self):
self._label_list.populate()
self._label_list.render_label()

def _init_elements(self):
def _init_elements(self) -> None:
self.setWindowTitle("Labelle GUI")
self.setWindowIcon(QIcon(str(ICON_DIR / "logo_small.png")))
self.setGeometry(200, 200, 1100, 400)
Expand All @@ -68,7 +68,7 @@ def _init_elements(self):
minimum_horizontal_margin_mm=self._dymo_labeler.minimum_horizontal_margin_mm,
)

def _init_connections(self):
def _init_connections(self) -> None:
self._label_list.renderPrintPreviewSignal.connect(self._update_preview_render)
self._label_list.renderPrintPayloadSignal.connect(self._update_print_render)
self._actions.print_label_signal.connect(self._on_print_label)
Expand All @@ -79,7 +79,7 @@ def _init_connections(self):
self._on_device_selected
)

def _init_layout(self):
def _init_layout(self) -> None:
self._actions.setParent(self._render_widget)
self._render.setParent(self._render_widget)

Expand All @@ -97,7 +97,7 @@ def _init_layout(self):
self._window_layout.addWidget(self._render_widget)
self.setLayout(self._window_layout)

def _on_settings_changed(self, settings: Settings):
def _on_settings_changed(self, settings: Settings) -> None:
assert self._dymo_labeler is not None
self._dymo_labeler.tape_size_mm = settings.tape_size_mm

Expand All @@ -121,13 +121,13 @@ def _on_settings_changed(self, settings: Settings):
self._label_list.setEnabled(is_ready)
self._render_widget.setEnabled(is_ready)

def _update_preview_render(self, preview_bitmap):
def _update_preview_render(self, preview_bitmap: Image.Image) -> None:
self._render.update_preview_render(preview_bitmap)

def _update_print_render(self, label_bitmap_to_print):
def _update_print_render(self, label_bitmap_to_print) -> None:
self._label_bitmap_to_print = label_bitmap_to_print

def _on_print_label(self):
def _on_print_label(self) -> None:
try:
if self._label_bitmap_to_print is None:
raise RuntimeError("No label to print! Call update_label_render first.")
Expand All @@ -136,12 +136,12 @@ def _on_print_label(self):
except DymoLabelerPrintError as err:
crash_msg_box(self, "Printing Failed!", err)

def _on_device_selected(self):
def _on_device_selected(self) -> None:
self._dymo_labeler.device = self._device_selector.selected_device
self._settings_toolbar.on_settings_changed()


def parse(app):
def parse(app) -> None:
"""Parse the arguments and options of the given app object."""
parser = QCommandLineParser()
parser.addHelpOption()
Expand All @@ -156,7 +156,7 @@ def parse(app):
set_not_verbose()


def main():
def main() -> None:
configure_logging()
with system_run():
app = QApplication(sys.argv)
Expand Down
12 changes: 6 additions & 6 deletions src/labelle/gui/q_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,16 @@ def __init__(self, parent: Optional[QWidget] = None):
self._init_connections()
self._init_layout()

def _init_elements(self):
def _init_elements(self) -> None:
printer_icon = QIcon.fromTheme("printer")
self._print_button.setIcon(printer_icon)
self._print_button.setFixedSize(64, 64)
self._print_button.setIconSize(QSize(48, 48))

def _init_connections(self):
def _init_connections(self) -> None:
self._print_button.clicked.connect(self._on_print_label)

def _init_layout(self):
def _init_layout(self) -> None:
layout = QVBoxLayout(self)
layout.addWidget(
self._print_button, alignment=QtCore.Qt.AlignmentFlag.AlignRight
Expand All @@ -46,16 +46,16 @@ def _init_layout(self):
self._error_label, alignment=QtCore.Qt.AlignmentFlag.AlignCenter
)

def _on_print_label(self):
def _on_print_label(self) -> None:
self.print_label_signal.emit()

def clear_error(self):
def clear_error(self) -> None:
self._error_label.setText("")
self._last_error = None
self._print_button.setEnabled(True)
self._print_button.setCursor(Qt.CursorShape.ArrowCursor)

def set_error(self, error: str):
def set_error(self, error: str) -> None:
if self._last_error == error:
return
self._last_error = error
Expand Down
12 changes: 6 additions & 6 deletions src/labelle/gui/q_device_selector.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,17 @@ def __init__(self, parent=None):
self._last_scan_error_changed()
self.selectedDeviceChangedSignal.emit()

def _init_elements(self):
def _init_elements(self) -> None:
self.device_manager = OnlineDeviceManager()

def _init_connections(self):
def _init_connections(self) -> None:
self.device_manager.devices_changed_signal.connect(self.repopulate)
self.device_manager.last_scan_error_changed_signal.connect(
self._last_scan_error_changed
)
self._devices.currentIndexChanged.connect(self._index_changed)

def repopulate(self):
def repopulate(self) -> None:
old_hashes = {device.hash for device in self.device_manager.devices}
self._devices.clear()
for idx, device in enumerate(self.device_manager.devices):
Expand All @@ -71,19 +71,19 @@ def repopulate(self):
if new_hashes != old_hashes:
self.selectedDeviceChangedSignal.emit()

def _index_changed(self, index):
def _index_changed(self, index) -> None:
if index >= 0:
self._selected_device = self.device_manager.devices[index]
else:
self._selected_device = None
self.selectedDeviceChangedSignal.emit()

def _last_scan_error_changed(self):
def _last_scan_error_changed(self) -> None:
last_scan_error = self.device_manager.last_scan_error or ""
self._error_label.setText(str(last_scan_error))
self.repopulate()

def _init_layout(self):
def _init_layout(self) -> None:
self._devices.setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy.AdjustToContents)
self._action_devices = self.addWidget(self._devices)
self._action_error_label = self.addWidget(self._error_label)
Expand Down
12 changes: 6 additions & 6 deletions src/labelle/gui/q_label_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@


class FontStyle(QComboBox):
def __init__(self):
def __init__(self) -> None:
super().__init__()
# Populate font_style
for font_path in get_available_fonts():
Expand Down Expand Up @@ -67,17 +67,17 @@ class BaseLabelWidget(QWidget):

itemRenderSignal = QtCore.pyqtSignal(name="itemRenderSignal")

def content_changed(self):
def content_changed(self) -> None:
"""Emit the itemRenderSignal when the content of the label is changed."""
self.itemRenderSignal.emit()

@property
def render_engine_impl(self):
def render_engine_impl(self) -> None:
"""Abstract method for getting the render engine of the label."""
pass

@property
def render_engine(self):
def render_engine(self) -> Optional[RenderEngine]:
try:
return self.render_engine_impl
except RenderEngineException as err:
Expand Down Expand Up @@ -151,7 +151,7 @@ def __init__(self, render_context: RenderContext, parent: Optional[QWidget] = No
self.align.currentTextChanged.connect(self.content_changed)
self.setLayout(layout)

def content_changed(self):
def content_changed(self) -> None:
"""Manage changes to the label contents.
In particular, update the height of the label and emit the itemRenderSignal
Expand Down Expand Up @@ -357,7 +357,7 @@ def set_text_fields_visibility(self, visible):
QIcon(str(ICON_DIR / "barcode_icon.png")).pixmap(32, 32)
)

def toggle_text_fields_and_rerender(self):
def toggle_text_fields_and_rerender(self) -> None:
is_checked = self.show_text_checkbox.isChecked()
self.set_text_fields_visibility(is_checked)
self.content_changed() # Trigger rerender
Expand Down
Loading

0 comments on commit 9a3b9bf

Please sign in to comment.