Skip to content
Open
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
100 changes: 99 additions & 1 deletion src/lob_hlpr/hlpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
class LobHlpr:
"""Helper functions for Lobaro tools."""

LOB_PRINT_LOG_PATH = None

@staticmethod
def sn_vid_pid_to_regex(
sn: str | None = None, vid: str | None = None, pid: str | None = None
Expand Down Expand Up @@ -55,14 +57,16 @@ def sn_vid_pid_to_regex(
return f"VID:PID={vid or '.*'}:{pid or '.*'}.+SER={sn}"

@staticmethod
def lob_print(log_path: str, *args, **kwargs):
def lob_print(log_path: str | None, *args, **kwargs):
"""Print to the console and log to a file.

The log file is rotated when it reaches 256MB and the last two
log files are kept. This can write all log messages to the log file
only if the log handlers are set (i.e. basicConfig loglevel is Debug).
"""
print(*args, flush=True, **kwargs)
if log_path is None and LobHlpr.LOB_PRINT_LOG_PATH is None:
return
# get the directory from the log_path
log_dir = os.path.dirname(log_path)
os.makedirs(log_dir, exist_ok=True)
Expand Down Expand Up @@ -148,6 +152,100 @@ def parse_dmc(dmc):

return erp_prod_number, batch_number, pcba_serial_number, article_number

@staticmethod
def verify_dmc_prefix(dmc: str, allowed_prefixes: list[str]) -> str:
"""Verify if the DMC starts with an allowed prefix.

If it does, cut any repeated scans
(e.g. MPP-OR019504_1-00781MPP-OR019504_1-00781)
to one DMC and return it, otherwise return an empty string.

Args:
dmc (str): The scanned DMC, digital manufacturer code.
allowed_prefixes (list[str]): List of allowed DMC prefixes.

Returns:
str: The (first) DMC if it starts with an allowed prefix,
otherwise an empty string.
"""
if not allowed_prefixes:
# No prefixes configured, so no check needed
LobHlpr.lob_print(
LobHlpr.LOB_PRINT_LOG_PATH,
"No DMC prefixes configured, skipping prefix check.",
)
return dmc
for prefix in allowed_prefixes:
if dmc.startswith(prefix):
return dmc
LobHlpr.lob_print(
LobHlpr.LOB_PRINT_LOG_PATH,
f"DMC {dmc} does not start with any of the allowed prefixes: "
f"{allowed_prefixes}",
)
return ""

@staticmethod
def verify_dmc_customer(dmc: str, allowed_suffix: list[str]) -> bool:
"""Verify if the DMC is allowed for the current customer config.

This is done by checking if the article number ends with letter(s),
and if customer letter(s) are configured, it must match an allowed string.

Args:
dmc (str): The scanned DMC, digital manufacturer code.
allowed_suffix (list[str]): List of allowed customer article suffixes.

Returns:
bool: True if the DMC is valid for the customer, False otherwise.
"""
_, _, serial_no, article_no = LobHlpr.parse_dmc(dmc)
# serial no should be all digits,
# otherwise it may contain the nrf 2did as well
if not serial_no.isdigit():
LobHlpr.lob_print(
LobHlpr.LOB_PRINT_LOG_PATH,
f"Serial number {serial_no} in DMC {dmc} is not all digits!",
)
return False
if not allowed_suffix:
# No customer letters configured, so no check needed
LobHlpr.lob_print(
LobHlpr.LOB_PRINT_LOG_PATH,
"No customer letters configured, skipping customer check.",
)
return True
if not article_no:
# No article number to check
LobHlpr.lob_print(
LobHlpr.LOB_PRINT_LOG_PATH,
"No article number found in DMC, skipping customer check.",
)
return True
if not article_no[-1].isalpha():
# No letters at the end, so no customer letters to check
LobHlpr.lob_print(
LobHlpr.LOB_PRINT_LOG_PATH,
f"No customer letters in article number {article_no}, "
f"skipping customer check.",
)
return True
article_cust_letters = re.match(r".*([^0-9\W]+)$", article_no)
cust_letters = article_cust_letters.group(1) # type: ignore[union-attr]
if cust_letters not in allowed_suffix:
LobHlpr.lob_print(
LobHlpr.LOB_PRINT_LOG_PATH,
f"Customer letters {cust_letters} in article number {article_no} "
f"are not allowed, must be one of {allowed_suffix}.",
)
return False
LobHlpr.lob_print(
LobHlpr.LOB_PRINT_LOG_PATH,
f"Customer letters {cust_letters} in article number {article_no} "
f"are allowed, continuing.",
)
return True

@staticmethod
def extract_identifier_from_hexfile(hex_str: str):
"""Extract the identifier from a hex file.
Expand Down
45 changes: 45 additions & 0 deletions tests/test_lob_hlpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,51 @@ def test_parse_dmc_fail():
hlp.parse_dmc("MPP-OR023282_1")


def test_verify_dmc_prefix_pass():
"""Test verify_dmc_prefix function passing cases."""
assert (
hlp.verify_dmc_prefix("MPP-OR019504_1-00781", ["MPP", "SOMETHING-ELSE"])
== "MPP-OR019504_1-00781"
)
assert (
hlp.verify_dmc_prefix("MPP-M0011803L-OR024569_3-0187", ["MPP"])
== "MPP-M0011803L-OR024569_3-0187"
)
assert hlp.verify_dmc_prefix("MPP-OR019504_1-00781", []) == "MPP-OR019504_1-00781"


def test_verify_dmc_prefix_fail():
"""Test verify_dmc_prefix function failing cases."""
assert hlp.verify_dmc_prefix("MPP-OR019504_1-00781", ["123", "456"]) == ""


def test_verify_dmc_customer_pass():
"""Test verify_dmc_customer function passing cases."""
assert hlp.verify_dmc_customer("MPP-M0011803L-OR024569_3-0187", ["L"]) is True
assert hlp.verify_dmc_customer("MPP-M0011803L-OR024569_3-0187", ["B"]) is False
assert hlp.verify_dmc_customer("MPP-OR019504_1-00781", []) is True


def test_verify_dmc_customer_no_sn_digit():
"""Test verify_dmc_customer function with no digit at the end of article number."""
assert hlp.verify_dmc_customer("MPP-M0011803L-OR024569_3-SNNOTDIGIT", []) is False


def test_verify_dmc_customer_no_article_number():
"""Test verify_dmc_customer function with no article number."""
assert hlp.verify_dmc_customer("MPP-M0011803L_3-0187", ["L"]) is True


def test_verify_dmc_customer_article_num_is_not_alpha():
"""Test verify_dmc_customer function with article number not ending with letters."""
assert hlp.verify_dmc_customer("MPP-M0011803-OR024569_3-0187", ["L"]) is True


def test_verify_dmc_customer_article_num_is_not_article_cust_letters():
"""Test verify_dmc_customer with article number not having customer letters."""
assert hlp.verify_dmc_customer("MPP-M0011803L-OR024569_3-0187", ["X"]) is False


# A bit of looking through a hex file and manual parsing allows me to provide
# the following data for testing.
HEX_STRINGS = [
Expand Down