Skip to content

Commit

Permalink
Merge pull request computerlyrik#108 from tomers/tomer_fixes
Browse files Browse the repository at this point in the history
Tomer fixes
  • Loading branch information
maresb authored Jan 20, 2024
2 parents e0f0029 + 0a5a125 commit 30a775f
Show file tree
Hide file tree
Showing 20 changed files with 203 additions and 109 deletions.
1 change: 1 addition & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ ARG pip_deps="\
pre-commit \
ruff \
tox \
mypy \
"
RUN pip install --upgrade pip \
&& pip install ${pip_deps}
Expand Down
4 changes: 3 additions & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
"eamodio.gitlens",
"ms-azuretools.vscode-docker",
"tamasfe.even-better-toml",
"zhoufeng.pyqt-integration"
"zhoufeng.pyqt-integration",
"charliermarsh.ruff",
"ms-python.mypy-type-checker"
]
}
},
Expand Down
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
.Python
env/
bin/
lib/
lib64/
parts/
var/
Expand Down
5 changes: 5 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,8 @@ repos:
rev: v1.0.0
hooks:
- id: check-json5

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.8.0
hooks:
- id: mypy
8 changes: 7 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ source = "https://github.com/computerlyrik/dymoprint"
tracker = "https://github.com/computerlyrik/dymoprint/issues"

[project.scripts]
dymoprint = "dymoprint.command_line:main"
dymoprint = "dymoprint.cli.cli:main"
dymoprint_gui = "dymoprint.gui.gui:main"

[tool.hatch.version]
Expand Down Expand Up @@ -183,3 +183,9 @@ ignore = [
"ISC002", # multi-line-implicit-string-concatenation
]
target-version = "py38"

[tool.mypy]
exclude = ["_vendor"]
ignore_missing_imports = true
check_untyped_defs = true
install_types = true
4 changes: 2 additions & 2 deletions src/dymoprint/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .labeler import DymoLabeler
from .metadata import __version__
from dymoprint.lib.labeler import DymoLabeler
from dymoprint.metadata import __version__

__all__ = ["__version__", "DymoLabeler"]
55 changes: 31 additions & 24 deletions src/dymoprint/command_line.py → src/dymoprint/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,33 @@
# === END LICENSE STATEMENT ===

import argparse
import sys
import webbrowser
from pathlib import Path
from tempfile import NamedTemporaryFile

from PIL import Image, ImageOps

from . import __version__
from .constants import (
from dymoprint import __version__
from dymoprint.lib.constants import (
AVAILABLE_BARCODES,
DEFAULT_MARGIN_PX,
PIXELS_PER_MM,
USE_QR,
e_qrcode,
)
from .detect import detect_device
from .dymo_print_engines import DymoRenderEngine, print_label
from .font_config import available_fonts, font_filename
from .metadata import our_metadata
from .unicode_blocks import image_to_unicode
from .utils import die
from dymoprint.lib.detect import detect_device
from dymoprint.lib.dymo_print_engines import DymoRenderEngine, print_label
from dymoprint.lib.font_config import FontConfig, FontStyle, NoFontFound
from dymoprint.lib.unicode_blocks import image_to_unicode
from dymoprint.lib.utils import die
from dymoprint.metadata import our_metadata

FLAG_TO_STYLE = {
"r": FontStyle.REGULAR,
"b": FontStyle.BOLD,
"i": FontStyle.ITALIC,
"n": FontStyle.NARROW,
}


def parse_args():
Expand All @@ -48,6 +55,7 @@ def parse_args():
)
parser.add_argument(
"-s",
"--style",
choices=["r", "b", "i", "n"],
default="r",
help="Set fonts style (regular,bold,italic,narrow)",
Expand Down Expand Up @@ -177,21 +185,20 @@ def main():
render_engine = DymoRenderEngine(args.t)

# read config file
FONT_FILENAME = font_filename(args.s)
style = FLAG_TO_STYLE.get(args.style)
try:
font_config = FontConfig(font=args.font, style=style)
except NoFontFound as e:
valid_font_names = [f.stem for f in FontConfig.available_fonts()]
print(
f"Valid fonts are: {', '.join(valid_font_names)}.",
file=sys.stderr,
)
raise e

labeltext = args.text
font_filename = font_config.path

if args.font is not None:
if Path(args.font).is_file():
FONT_FILENAME = args.font
else:
try:
FONT_FILENAME = next(
f.absolute() for f in available_fonts() if args.font == f.stem
)
except StopIteration:
fonts = ",".join(f.stem for f in available_fonts())
die(f"Error: file '{args.font}' not found. Available fonts: {fonts}")
labeltext = args.text

# check if barcode, qrcode or text should be printed, use frames only on text
if args.qr and not USE_QR:
Expand Down Expand Up @@ -222,15 +229,15 @@ def main():
elif args.barcode_text:
bitmaps.append(
render_engine.render_barcode_with_text(
labeltext.pop(0), args.barcode_text, FONT_FILENAME, args.f
labeltext.pop(0), args.barcode_text, font_filename, args.f
)
)

if labeltext:
bitmaps.append(
render_engine.render_text(
text_lines=labeltext,
font_file_name=FONT_FILENAME,
font_file_name=font_filename,
frame_width_px=args.f,
font_size_ratio=int(args.scale) / 100.0,
align=args.a,
Expand Down
39 changes: 0 additions & 39 deletions src/dymoprint/font_config.py

This file was deleted.

8 changes: 4 additions & 4 deletions src/dymoprint/gui/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
)
from usb.core import NoBackendError, USBError

from dymoprint.constants import DEFAULT_MARGIN_PX, ICON_DIR
from dymoprint.detect import detect_device
from dymoprint.dymo_print_engines import DymoRenderEngine, print_label
from dymoprint.lib.constants import DEFAULT_MARGIN_PX, ICON_DIR
from dymoprint.lib.detect import DeviceDetectionError, detect_device
from dymoprint.lib.dymo_print_engines import DymoRenderEngine, print_label

from .q_dymo_labels_list import QDymoLabelList

Expand Down Expand Up @@ -194,7 +194,7 @@ def check_status(self):
try:
self.detected_device = detect_device()
is_enabled = True
except (NoBackendError, USBError) as e:
except (DeviceDetectionError, NoBackendError, USBError) as e:
self.error_label.setText(f"Error: {e}")
self.detected_device = None
self.error_label.setVisible(not is_enabled)
Expand Down
16 changes: 9 additions & 7 deletions src/dymoprint/gui/q_dymo_label_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,19 @@
QWidget,
)

from dymoprint.constants import AVAILABLE_BARCODES, ICON_DIR
from dymoprint.dymo_print_engines import DymoRenderEngine
from dymoprint.font_config import parse_fonts
from dymoprint.lib.constants import AVAILABLE_BARCODES, ICON_DIR
from dymoprint.lib.dymo_print_engines import DymoRenderEngine
from dymoprint.lib.font_config import FontConfig


class FontStyle(QComboBox):
def __init__(self):
super().__init__()
# Populate font_style
for name, font_path in parse_fonts():
self.addItem(name, font_path)
for font_path in FontConfig.available_fonts():
name = font_path.stem
absolute_path = font_path.absolute()
self.addItem(name, absolute_path)
self.setCurrentText("Carlito-Regular")


Expand All @@ -48,6 +50,8 @@ class BaseDymoLabelWidget(QWidget):
Abstract method to be implemented by subclasses for rendering the label.
"""

render_engine: DymoRenderEngine

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

def content_changed(self):
Expand Down Expand Up @@ -88,7 +92,6 @@ class TextDymoLabelWidget(BaseDymoLabelWidget):
itemRenderSignal: A signal emitted when the content of the label changes.
"""

render_engine: DymoRenderEngine
align: QComboBox
label: QPlainTextEdit
font_style: FontStyle
Expand Down Expand Up @@ -243,7 +246,6 @@ class BarcodeDymoLabelWidget(BaseDymoLabelWidget):
and barcode type.
"""

render_engine: DymoRenderEngine
label: QLineEdit
barcode_type_label: QLabel
barcode_type: QComboBox
Expand Down
26 changes: 17 additions & 9 deletions src/dymoprint/gui/q_dymo_labels_list.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
from typing import Optional

from PIL import Image
from PyQt6 import QtCore
from PyQt6.QtGui import QAction
from PyQt6.QtWidgets import QAbstractItemView, QListWidget, QListWidgetItem, QMenu

from .q_dymo_label_widgets import (
from dymoprint.gui.q_dymo_label_widgets import (
BarcodeDymoLabelWidget,
ImageDymoLabelWidget,
QrDymoLabelWidget,
TextDymoLabelWidget,
)
from dymoprint.lib.dymo_print_engines import DymoRenderEngine


class QDymoLabelList(QListWidget):
Expand Down Expand Up @@ -38,6 +42,8 @@ class QDymoLabelList(QListWidget):
"""

renderSignal = QtCore.pyqtSignal(Image.Image, name="renderSignal")
render_engine: DymoRenderEngine
itemWidget: TextDymoLabelWidget

def __init__(
self, render_engine, min_payload_len_px=0, justify="center", parent=None
Expand Down Expand Up @@ -66,7 +72,9 @@ def dropEvent(self, e) -> None:
super().dropEvent(e)
self.render_label()

def update_params(self, render_engine, min_payload_len_px=0, justify="center"):
def update_params(
self, render_engine: DymoRenderEngine, min_payload_len_px=0, justify="center"
):
"""Update the render engine used for rendering the label.
Args:
Expand Down Expand Up @@ -109,11 +117,11 @@ def contextMenuEvent(self, event):
event (QContextMenuEvent): The context menu event.
"""
contextMenu = QMenu(self)
add_text = contextMenu.addAction("Add Text")
add_qr = contextMenu.addAction("Add QR")
add_barcode = contextMenu.addAction("Add Barcode")
add_img = contextMenu.addAction("Add Image")
delete = contextMenu.addAction("Delete")
add_text: Optional[QAction] = contextMenu.addAction("Add Text")
add_qr: Optional[QAction] = contextMenu.addAction("Add QR")
add_barcode: Optional[QAction] = contextMenu.addAction("Add Barcode")
add_img: Optional[QAction] = contextMenu.addAction("Add Image")
delete: Optional[QAction] = contextMenu.addAction("Delete")
menu_click = contextMenu.exec(event.globalPos())

if menu_click == add_text:
Expand Down Expand Up @@ -149,8 +157,8 @@ def contextMenuEvent(self, event):
item_widget.itemRenderSignal.connect(self.render_label)
if menu_click == delete:
try:
item = self.itemAt(event.pos())
self.takeItem(self.indexFromItem(item).row()) # self.update()
item_to_delete = self.itemAt(event.pos())
self.takeItem(self.indexFromItem(item_to_delete).row()) # self.update()
except Exception as e: # noqa: BLE001
print(f"No item selected {e}")
self.render_label()
Original file line number Diff line number Diff line change
Expand Up @@ -89,17 +89,19 @@ def _init(self, code):
self._draw = ImageDraw.Draw(self._image)

def _paint_module(self, xpos, ypos, width, color):
size = [
size = (
(mm2px(xpos, self.dpi), mm2px(ypos, self.dpi)),
(
mm2px(xpos + width, self.dpi),
mm2px(ypos + self.module_height, self.dpi),
),
]
)
assert self._draw is not None
self._draw.rectangle(size, outline=color, fill=color)

def _finish(self):
# although Image mode set to "1", draw function writes white as 255
assert self._image is not None
self._image = self._image.point(lambda x: 1 if x > 0 else 0, mode="1")
return self._image

Expand Down
33 changes: 33 additions & 0 deletions src/dymoprint/lib/config_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from configparser import ConfigParser
from pathlib import Path

from platformdirs import user_config_dir


class SectionNotFound(Exception):
def __init__(self, config_file_path, section_name):
msg = f"Section {section_name} not fount in {config_file_path}"
super().__init__(msg)


class ConfigFile:
_CONFIG_FILE_PATH = Path(user_config_dir()) / "dymoprint.ini"
_config_parser = None

def __init__(self):
config_parser = ConfigParser()
if config_parser.read(self._CONFIG_FILE_PATH):
self._config_parser = config_parser

def section(self, section_name):
"""Return the given config file section as dict."""
if self._config_parser:
try:
return dict(self._config_parser[section_name])
except KeyError:
raise SectionNotFound(self._CONFIG_FILE_PATH, section_name) from None
return None

@property
def fonts_section(self):
return self.section("FONTS")
Loading

0 comments on commit 30a775f

Please sign in to comment.