Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Device dependent margins/config #54

Merged
merged 27 commits into from
Jul 4, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
d73626d
Add "DYMO LabelMANAGER PC II" device ID
FaBjE Jun 15, 2024
06f61ea
Add 24mm tape type
FaBjE Jun 16, 2024
3aecdc7
device specific init WIP
FaBjE Jun 18, 2024
1872e40
Add DeviceConfig class for each printer
FaBjE Jun 20, 2024
1b279b3
Please mypy...
FaBjE Jun 20, 2024
2353512
Fix usb device recognition
FaBjE Jun 21, 2024
dcc6234
Calculate margins instead of using lookup table
FaBjE Jun 21, 2024
040f2c2
Force sending an "exact printhead width" bitmap to the printer
FaBjE Jun 21, 2024
f907b8b
Fix config not updated when device set
FaBjE Jun 21, 2024
d64c977
Tested on LabelManager PnP
FaBjE Jun 21, 2024
a7def5e
replace all camels with snakes
FaBjE Jun 22, 2024
d8dcb3d
Cleanup supported device list syntax
FaBjE Jun 23, 2024
4fc8b68
Convert device config to dataclass
FaBjE Jun 23, 2024
1d36049
Convert labeler device-config to property
FaBjE Jun 23, 2024
d8b3b6d
Move get_tape_print_size_and_margins_px to labeler class tape_print_p…
FaBjE Jun 23, 2024
13fa9b9
Revert GUI supported_tape_sizes type
FaBjE Jun 23, 2024
424ec34
Remove fixed default tapesize (take highest supported as default)
FaBjE Jun 23, 2024
d342a04
Shorten matches_device_id function
FaBjE Jun 23, 2024
1786928
Fix code convention in if statement
FaBjE Jun 23, 2024
16d82e8
Shorten if statement
FaBjE Jun 23, 2024
e239867
Shorten if statement
FaBjE Jun 23, 2024
b390217
Let get_device_config_by_id raise exception if not supported
FaBjE Jun 23, 2024
0bdf8fd
Remove var / shorten line
FaBjE Jun 23, 2024
a4ed930
fix comment
FaBjE Jun 23, 2024
fdf3538
Clear up comment block
FaBjE Jun 23, 2024
0fa7ad5
Fix wrong var name
FaBjE Jun 23, 2024
7246473
Remove constant DPI values and calculations
FaBjE Jun 23, 2024
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 src/labelle/gui/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def _init_elements(self) -> None:
self._device_manager = DeviceManager()
self._dymo_labeler = DymoLabeler()
self._settings_toolbar.update_labeler_context(
supported_tape_sizes=self._dymo_labeler.SUPPORTED_TAPE_SIZES_MM,
supported_tape_sizes=self._dymo_labeler._deviceConfig.supportedTapeSizes,
maresb marked this conversation as resolved.
Show resolved Hide resolved
installed_tape_size=self._dymo_labeler.tape_size_mm,
minimum_horizontal_margin_mm=self._dymo_labeler.minimum_horizontal_margin_mm,
)
Expand Down
2 changes: 1 addition & 1 deletion src/labelle/gui/q_settings_toolbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def _init_elements(self) -> None:

def update_labeler_context(
self,
supported_tape_sizes: tuple[int, ...],
supported_tape_sizes: list[int],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really needed? In case the list is constant, it would be better as a convention to prefer tuple over list

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The amount of supported tape sizes varies from printer to printer. I got an error that I tried to change the "tuple" size. A quick google search gave this as a solution. If there is a better solution please elaborate.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, tuples are "immutable" so you should always generate a new one instead of modifying an old one.

Copy link
Contributor Author

@FaBjE FaBjE Jun 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed (It didn´t complain this time)

Edit:
Sorry, had to revert this:

src/labelle/gui/gui.py:66: error: Argument "supported_tape_sizes" to "update_labeler_context" of "QSettingsToolbar" has incompatible type "list[int]"; expected "tuple[int, ...]"  [arg-type]
Found 1 error in 1 file (checked 46 source files)

installed_tape_size: int,
minimum_horizontal_margin_mm: float,
) -> None:
Expand Down
140 changes: 126 additions & 14 deletions src/labelle/lib/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@
# either sysfs is unavailable or unusable by this script for some reason.
# Please beware that DEV_NODE must be set to None when not used, else you will
# be bitten by the NameError exception.
from enum import Enum
from enum import Enum, IntEnum
from pathlib import Path

import labelle.resources.fonts
import labelle.resources.icons
from labelle.lib.devices.device_config import DeviceConfig

try:
from pyqrcode import QRCode
Expand All @@ -34,19 +35,130 @@
"WARNING: This device is not confirmed to work with this software. Please "
"report your experiences in https://github.com/labelle-org/labelle/issues/4"
)
SUPPORTED_PRODUCTS = {
0x0011: "DYMO LabelMANAGER PC",
0x0015: "LabelPoint 350",
0x1001: "LabelManager PnP (no mode switch)",
0x1002: "LabelManager PnP (mode switch)",
0x1003: f"LabelManager 420P (no mode switch) {UNCONFIRMED_MESSAGE}",
0x1004: f"LabelManager 420P (mode switch) {UNCONFIRMED_MESSAGE}",
0x1005: "LabelManager 280 (no mode switch)",
0x1006: "LabelManager 280 (no mode switch)",
0x1007: f"LabelManager Wireless PnP (no mode switch) {UNCONFIRMED_MESSAGE}",
0x1008: f"LabelManager Wireless PnP (mode switch) {UNCONFIRMED_MESSAGE}",
0x1009: f"MobileLabeler {UNCONFIRMED_MESSAGE}",
}


# Supported USB device ID enumeration
class SUPPORTED_DEVICE_ID(IntEnum):
LABELMANAGER_PC = 0x0011
LABELPOINT_350 = 0x0015
LABELMANAGER_PC_II = 0x001C
LABELMANAGER_PNP_NO_MODE_SWITCH = 0x1001
LABELMANAGER_PNP_MODE_SWITCH = 0x1002
LABELMANAGER_420P_NO_MODE_SWITCH = 0x1003
LABELMANAGER_420P_MODE_SWITCH = 0x1004
LABELMANAGER_280P_NO_MODE_SWITCH = 0x1005
LABELMANAGER_280P_MODE_SWITCH = 0x1006
LABELMANAGER_WIRELESS_PNP_NO_MODE_SWITCH = 0x1007
LABELMANAGER_WIRELESS_PNP_MODE_SWITCH = 0x1008
MOBILE_LABELER = 0x1009


# Create supported products list
SUPPORTED_PRODUCTS = []
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using append is a dynamic operation. I think it would look better to do

SUPPORTED_PRODUCTS = [
    DeviceConfig(
        ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll try (the append was just copied from an example)


# ---- Supported USB Devices configuration ----
SUPPORTED_PRODUCTS.append(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that eventually we should move these out of the code, into a JSON file. If possible, please try to do it. In not, we can try refactor it later.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need a proper data model(1) for device models(2). (The first "model" in that sentence means "implementation of a schema" while the second "model" refers to a particular product that is sold by a company.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I was a bit confused You do already define DeviceConfig.

I'm wondering how to achieve this elegantly. I agree that it's in principle better to define these things out-of-code like in JSON. However, that unfortunately would require deserialization. Pydantic is a popular library for this, but then we're adding more project dependencies and a lot of complexity, also in the code.

The way I see it, we have two main options:

  1. Separate the device definition from code, perform deserialization, probably add a dependency on something like Pydantic.
  2. Keep the device definitions as code, but switch to NamedTuple or dataclass.

Another disadvantage to 1. is that editing the config would involve editing serialized data which can be a real pain. An advantage to 2. is that code tools like mypy will automatically perform validation for the data-as-code.

I'm leaning more towards 2.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I was trying to achieve here is a what in C would be "array of structs" for the "const" configuration.
If you have any suggestions how to do this elegantly in python, let me know...

My idea was that the (existing) labeler class took this as input to know the device's exact properties.

I agree that having this out of code would be nice. But can we please keep this contained?
I started out with "just adding my printer", and it is getting a bit out of hand already imho.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Converted DeviceConfig to a dataclass

DeviceConfig(
"DYMO LabelMANAGER PC",
[int(SUPPORTED_DEVICE_ID.LABELMANAGER_PC)],
# ToDo: Validate config!
128,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's hard to understand from reading this what each field means. Please explicitly name each field.

Copy link
Contributor

@maresb maresb Jun 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be explicit, this is as simple as

DeviceConfig(
    name="DYMO LabelMANAGER PC",
    deviceIDs=[int(SUPPORTED_DEVICE_ID.LABELMANAGER_PC)],
    ...

Also, the use here of SUPPORTED_DEVICE_ID seems very indirect to me. Why not just do

    deviceIDs=[0x0011],

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If that is possible can you give me a syntax example? (It would definitely be a lot clearer)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@FaBjE that was an explicit example, and should work without other modifications to your code if you continue the obvious pattern. (Python lets you specify the names of positional arguments in the function invocation.) Does this make sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn´t see your example at first. I had this page already open I guess.
But thanks! I will try to add.

I added the enum because before the DeviceConfig class I checked with if-else in the code which properties applied to the printer (Based on the device ID), but that was ugly imho.
I agree it is kind of redundant now. Shall I remove it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's an example:

def f(x, y):
    return 2 * x + y

f(y=1, x=2)  # 5

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

[6, 9, 12, 19],
{6: (44, 85), 9: (31, 94), 12: (38, 117), 19: (2, 127)},
)
)
SUPPORTED_PRODUCTS.append(
DeviceConfig(
"LabelPoint 350",
[int(SUPPORTED_DEVICE_ID.LABELPOINT_350)],
# ToDo: Validate config!
64,
[6, 9, 12],
{6: (44, 85), 9: (31, 94), 12: (38, 117)},
)
)
SUPPORTED_PRODUCTS.append(
DeviceConfig(
"DYMO LabelMANAGER PC II",
[int(SUPPORTED_DEVICE_ID.LABELMANAGER_PC_II)],
128,
[6, 9, 12, 19, 24],
{6: (44, 85), 9: (31, 94), 12: (38, 117), 19: (2, 127), 24: (2, 127)},
)
)
SUPPORTED_PRODUCTS.append(
DeviceConfig(
"LabelManager PnP",
[
int(SUPPORTED_DEVICE_ID.LABELMANAGER_PNP_NO_MODE_SWITCH),
int(SUPPORTED_DEVICE_ID.LABELMANAGER_PNP_MODE_SWITCH),
],
# ToDo: Validate config!
64,
[6, 9, 12],
{6: (44, 85), 9: (31, 94), 12: (38, 117)},
)
)
SUPPORTED_PRODUCTS.append(
DeviceConfig(
f"LabelManager 420P {UNCONFIRMED_MESSAGE}",
[
int(SUPPORTED_DEVICE_ID.LABELMANAGER_420P_NO_MODE_SWITCH),
int(SUPPORTED_DEVICE_ID.LABELMANAGER_420P_MODE_SWITCH),
],
# ToDo: Validate config!
64,
[6, 9, 12],
{6: (44, 85), 9: (31, 94), 12: (38, 117)},
)
)
SUPPORTED_PRODUCTS.append(
DeviceConfig(
"LabelManager 280",
[
int(SUPPORTED_DEVICE_ID.LABELMANAGER_280P_MODE_SWITCH),
int(SUPPORTED_DEVICE_ID.LABELMANAGER_280P_NO_MODE_SWITCH),
],
# ToDo: Validate config!
64,
[6, 9, 12],
{6: (44, 85), 9: (31, 94), 12: (38, 117)},
)
)
SUPPORTED_PRODUCTS.append(
DeviceConfig(
f"LabelManager Wireless PnP {UNCONFIRMED_MESSAGE}",
[
int(SUPPORTED_DEVICE_ID.LABELMANAGER_WIRELESS_PNP_NO_MODE_SWITCH),
int(SUPPORTED_DEVICE_ID.LABELMANAGER_WIRELESS_PNP_MODE_SWITCH),
],
# ToDo: Validate config!
64,
[6, 9, 12],
{6: (44, 85), 9: (31, 94), 12: (38, 117)},
)
)
SUPPORTED_PRODUCTS.append(
DeviceConfig(
f"MobileLabeler {UNCONFIRMED_MESSAGE}",
[int(SUPPORTED_DEVICE_ID.MOBILE_LABELER)],
# ToDo: Validate config!
64,
[6, 9, 12],
{6: (44, 85), 9: (31, 94), 12: (38, 117)},
)
)

# Simulator configuration
SIMULATOR_CONFIG = DeviceConfig(
"Simulator",
[0],
128,
[6, 9, 12, 19, 24],
{6: (44, 85), 9: (31, 94), 12: (38, 117), 19: (2, 127), 24: (2, 127)},
)


DEV_VENDOR = 0x0922

PRINTER_INTERFACE_CLASS = 0x07
Expand Down
71 changes: 71 additions & 0 deletions src/labelle/lib/devices/device_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
from __future__ import annotations

import logging
from typing import Tuple

LOG = logging.getLogger(__name__)


class DeviceConfig:
"""Configuration object for the capabilities of a label printer."""

name: str
"""Name of this device"""

deviceIDs: list[int]
"""List of USB Device ID's this device can identify as"""

printHeadSizePixels: int
"""Size of the print head in pixels (use calibration routine to determine)"""

supportedTapeSizes: list[int]
"""List of supported tape sizes in mm"""

marginsPerTape: dict[int, Tuple[int, int]]
"""
Dictonary of print margins per tape size
Entry: TapeSizeMM : (topMarginInPx, bottomMarginInPx)
Use the calibration routine to determine these for each tape size
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a link here to a markdown document under /doc which describes what the calibration routine is.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will check

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately there is no document at this moment. I think we need to add a link when it is there.

"""

def __init__(
self,
name: str,
deviceIDs: list[int],
maresb marked this conversation as resolved.
Show resolved Hide resolved
printHeadSizePixels: int,
supportedTapeSizes: list[int],
marginsPerTape: dict[int, Tuple[int, int]],
):
"""Initialize a Labeler config object."""
self.name = name
self.deviceIDs = deviceIDs
self.printHeadSizePixels = printHeadSizePixels
self.supportedTapeSizes = supportedTapeSizes
self.marginsPerTape = marginsPerTape
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe define the class as @dataclass. https://docs.python.org/3/library/dataclasses.html

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I'd probably use a NamedTuple which is simpler, but either should work.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure of the pro's and con's of both. But I think dataclass is easier to convert to?
I'll give it a shot

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made dataclass


def matches_device_id(self, idValue: int) -> bool:
"""Check if the a device ID matches this config."""
if idValue in self.deviceIDs:
return True
else:
return False
Copy link
Contributor

@tomers tomers Jun 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure a function is really needed for this, as it is rather short, and can be replaced with a simple expression. In any case, it should be refactored as follows:

return idValue in self.deviceIDs

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix. It seemed more "contained" to me than just accessing the array itself from outside the object.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed


def get_tape_print_margins(self, tapeSizeMM: int) -> tuple[int, int]:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also here, tape_size_mm, not tapeSizeMM (I will refrain now from commenting of improper casing).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do 😉 I'll do a re-check of my work.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Outdated/fixed

"""Get print margins for a specific tape size.

:param tapeSizeMM: Tape size in mm
:return: Margins tuple, None if not supported
"""
if tapeSizeMM in self.supportedTapeSizes:
if tapeSizeMM in self.marginsPerTape:
# Return specified margins
return self.marginsPerTape[tapeSizeMM]
else:
# No specific margins set, return default
return (0, 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return self.marginsPerTape.get(tapeSizeMM, (0, 0))

or even better:

DEFAULT_MARGINS = (0, 0)  # put this on top of file
return self.marginsPerTape.get(tapeSizeMM, DEFAULT_MARGINS)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, will fix. (these are the kind of things you have no clue about when using a new language)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Outdated

else:
# Tape size not supported
raise ValueError(
f"Unsupported tape size {tapeSizeMM}mm. "
f"Supported sizes: {self.supportedTapeSizes}mm"
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As coding convention, instead of:

    if term:
        # some very long logic
    else:
        raise ...

do:

    if term:
        raise ...
    # some very long logic

This reduces nesting.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed (now in dymo_labeler.py)

20 changes: 19 additions & 1 deletion src/labelle/lib/devices/device_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
from usb.core import NoBackendError, USBError

from labelle.lib.constants import (
SUPPORTED_DEVICE_ID,
SUPPORTED_PRODUCTS,
UNCONFIRMED_MESSAGE,
)
from labelle.lib.devices.device_config import DeviceConfig
from labelle.lib.devices.usb_device import UsbDevice

LOG = logging.getLogger(__name__)
Expand Down Expand Up @@ -80,8 +82,24 @@ def find_and_select_device(self, patterns: list[str] | None = None) -> UsbDevice
LOG.debug(dev.device_info)
dev = devices[0]
if dev.is_supported:
msg = f"Recognized device as {SUPPORTED_PRODUCTS[dev.id_product]}"
msg = f"Recognized device as \
{SUPPORTED_PRODUCTS[SUPPORTED_DEVICE_ID(dev.id_product)]}"
else:
msg = f"Unrecognized device: {hex(dev.id_product)}. {UNCONFIRMED_MESSAGE}"
LOG.debug(msg)
return dev


def get_device_config_by_id(idValue: int) -> DeviceConfig | None:
"""Get a labeler device config with USB ID.

:param idValue: USB ID value
:return: Device config, None if not found
"""
#
for device in SUPPORTED_PRODUCTS:
if device.matches_device_id(idValue) is True:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove is True. It will work the same

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, will fix

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

return device

# No device config found
return None
24 changes: 19 additions & 5 deletions src/labelle/lib/devices/dymo_labeler.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
from PIL import Image
from usb.core import NoBackendError, USBError

from labelle.lib.constants import ESC, SYN
from labelle.lib.constants import ESC, SIMULATOR_CONFIG, SYN
from labelle.lib.devices.device_config import DeviceConfig
from labelle.lib.devices.device_manager import get_device_config_by_id
from labelle.lib.devices.usb_device import UsbDevice, UsbDeviceError
from labelle.lib.utils import mm_to_px

Expand Down Expand Up @@ -236,27 +238,39 @@ def _raw_print_label(self, lines: list[list[int]]):

class DymoLabeler:
_device: UsbDevice | None
_deviceConfig: DeviceConfig
tape_size_mm: int

LABELER_DISTANCE_BETWEEN_PRINT_HEAD_AND_CUTTER_MM = 8.1
LABELER_PRINT_HEAD_HEIGHT_MM = 8.2
SUPPORTED_TAPE_SIZES_MM = (19, 12, 9, 6)
DEFAULT_TAPE_SIZE_MM = 12

def __init__(
self,
tape_size_mm: int | None = None,
device: UsbDevice | None = None,
):
self._device = device

if self._device is not None:
# Retrieve device config
foundConfig = get_device_config_by_id(self._device.id_product)
if foundConfig is not None:
self._deviceConfig = foundConfig
else:
raise ValueError(f"Unsupported device type {self._device.id_product}")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As before, style comment. Please use the following convention:

            if foundConfig is None:
                raise ValueError(f"Unsupported device type {self._device.id_product}")
            self._deviceConfig = foundConfig

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you return None from the function and raise here, instead of raising in the function itself, and then you will not have to test returned value from the function (and change its type to also support None).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question...
Stupid answer: I learned about the raising exceptions later on.

will fix.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

else:
# Use simulator config
self._deviceConfig = SIMULATOR_CONFIG

if tape_size_mm is None:
tape_size_mm = self.DEFAULT_TAPE_SIZE_MM
if tape_size_mm not in self.SUPPORTED_TAPE_SIZES_MM:
if tape_size_mm not in self._deviceConfig.supportedTapeSizes:
raise ValueError(
f"Unsupported tape size {tape_size_mm}mm. "
f"Supported sizes: {self.SUPPORTED_TAPE_SIZES_MM}"
f"Supported sizes: {self._deviceConfig.supportedTapeSizes}mm"
)
self.tape_size_mm = tape_size_mm
self._device = device

@property
def height_px(self):
Expand Down