From 86cf2ba63f4c4774647075b338bf012888d94669 Mon Sep 17 00:00:00 2001 From: Daniel Morais Date: Wed, 26 Jul 2023 14:25:50 +0200 Subject: [PATCH] Fix CI issues (Linter on Python code & Type checking) --- speculos/main.py | 1 - speculos/mcu/bagl_font.py | 47 +++++++++++++++++++------------------- speculos/mcu/nbgl.py | 2 +- speculos/mcu/ocr.py | 44 ++++++++++++++++++----------------- speculos/mcu/rle_custom.py | 26 ++++++++++++++------- speculos/mcu/seproxyhal.py | 1 + 6 files changed, 67 insertions(+), 54 deletions(-) diff --git a/speculos/main.py b/speculos/main.py index 6b7b3bf3..3029df71 100644 --- a/speculos/main.py +++ b/speculos/main.py @@ -15,7 +15,6 @@ import sys import threading import pkg_resources -from distutils.spawn import find_executable from elftools.elf.elffile import ELFFile from mnemonic import mnemonic from typing import Optional, Type diff --git a/speculos/mcu/bagl_font.py b/speculos/mcu/bagl_font.py index 40cb8e73..02134dd2 100644 --- a/speculos/mcu/bagl_font.py +++ b/speculos/mcu/bagl_font.py @@ -3061,29 +3061,30 @@ ] FONTS = [ - Font(BAGL_FONT_LUCIDA_CONSOLE_8PX, 1, 8, 16, 0, 0x0020, 0x00ff, charactersLUCIDA_CONSOLE_6PT_8H, - bitmapLUCIDA_CONSOLE_6PT_8H), - Font(BAGL_FONT_OPEN_SANS_LIGHT_16_22PX, 4, 22, 16, 0, 0x0020, 0x007f, charactersOPEN_SANS_LIGHT_16_22PX, - bitmapOPEN_SANS_LIGHT_16_22PX), - Font(BAGL_FONT_OPEN_SANS_REGULAR_8_11PX, 4, 11, 8, 0, 0x0020, 0x007f, charactersOPEN_SANS_REGULAR_8_11PX, - bitmapOPEN_SANS_REGULAR_8_11PX), - Font(BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, 4, 14, 10, 0, 0x0020, 0x007F, charactersOPEN_SANS_REGULAR_10_13PX, - bitmapOPEN_SANS_REGULAR_10_13PX), - Font(BAGL_FONT_OPEN_SANS_EXTRABOLD_11px, 1, 12, 9, 0, 0x0020, 0x007F, charactersOPEN_SANS_EXTRABOLD_11PX, - bitmapOPEN_SANS_EXTRABOLD_11PX), - Font(BAGL_FONT_OPEN_SANS_REGULAR_11px, 1, 12, 9, 0, 0x0020, 0x007F, charactersOPEN_SANS_REGULAR_11PX, - bitmapOPEN_SANS_REGULAR_11PX), - Font(BAGL_FONT_OPEN_SANS_LIGHT_16px, 1, 18, 13, 0, 0x0020, 0x007F, charactersOPEN_SANS_LIGHT_16PX, - bitmapOPEN_SANS_LIGHT_16PX), - Font(BAGL_FONT_OPEN_SANS_SEMIBOLD_10_13PX, 4, 14, 10, 0, 0x0020, 0x007f, charactersOPEN_SANS_SEMIBOLD_10_13PX, - bitmapOPEN_SANS_SEMIBOLD_10_13PX), - Font(BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, 4, 11, 8, 0, 0x0020, 0x007f, charactersOPEN_SANS_SEMIBOLD_8_11PX, - bitmapOPEN_SANS_SEMIBOLD_8_11PX), - Font(BAGL_FONT_OPEN_SANS_REGULAR_11_14PX, 4, 16, 12, 0, 0x0020, 0x007f, charactersOPEN_SANS_REGULAR_11_14PX, - bitmapOPEN_SANS_REGULAR_11_14PX), - Font(BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, 4, 16, 12, 0, 0x0020, 0x007f, charactersOPEN_SANS_SEMIBOLD_11_16PX, - bitmapOPEN_SANS_SEMIBOLD_11_16PX), - Font(BAGL_FONT_SYMBOLS_0, 4, 16, 16, 0, 0x0000, 0x0006, charactersSYMBOLS_0, bitmapSYMBOLS_0) + Font(BAGL_FONT_LUCIDA_CONSOLE_8PX, 1, 8, 16, 0, 0x0020, 0x00ff, + charactersLUCIDA_CONSOLE_6PT_8H, bitmapLUCIDA_CONSOLE_6PT_8H), + Font(BAGL_FONT_OPEN_SANS_LIGHT_16_22PX, 4, 22, 16, 0, 0x0020, 0x007f, + charactersOPEN_SANS_LIGHT_16_22PX, bitmapOPEN_SANS_LIGHT_16_22PX), + Font(BAGL_FONT_OPEN_SANS_REGULAR_8_11PX, 4, 11, 8, 0, 0x0020, 0x007f, + charactersOPEN_SANS_REGULAR_8_11PX, bitmapOPEN_SANS_REGULAR_8_11PX), + Font(BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, 4, 14, 10, 0, 0x0020, 0x007F, + charactersOPEN_SANS_REGULAR_10_13PX, bitmapOPEN_SANS_REGULAR_10_13PX), + Font(BAGL_FONT_OPEN_SANS_EXTRABOLD_11px, 1, 12, 9, 0, 0x0020, 0x007F, + charactersOPEN_SANS_EXTRABOLD_11PX, bitmapOPEN_SANS_EXTRABOLD_11PX), + Font(BAGL_FONT_OPEN_SANS_REGULAR_11px, 1, 12, 9, 0, 0x0020, 0x007F, + charactersOPEN_SANS_REGULAR_11PX, bitmapOPEN_SANS_REGULAR_11PX), + Font(BAGL_FONT_OPEN_SANS_LIGHT_16px, 1, 18, 13, 0, 0x0020, 0x007F, + charactersOPEN_SANS_LIGHT_16PX, bitmapOPEN_SANS_LIGHT_16PX), + Font(BAGL_FONT_OPEN_SANS_SEMIBOLD_10_13PX, 4, 14, 10, 0, 0x0020, 0x007f, + charactersOPEN_SANS_SEMIBOLD_10_13PX, bitmapOPEN_SANS_SEMIBOLD_10_13PX), + Font(BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, 4, 11, 8, 0, 0x0020, 0x007f, + charactersOPEN_SANS_SEMIBOLD_8_11PX, bitmapOPEN_SANS_SEMIBOLD_8_11PX), + Font(BAGL_FONT_OPEN_SANS_REGULAR_11_14PX, 4, 16, 12, 0, 0x0020, 0x007f, + charactersOPEN_SANS_REGULAR_11_14PX, bitmapOPEN_SANS_REGULAR_11_14PX), + Font(BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, 4, 16, 12, 0, 0x0020, 0x007f, + charactersOPEN_SANS_SEMIBOLD_11_16PX, bitmapOPEN_SANS_SEMIBOLD_11_16PX), + Font(BAGL_FONT_SYMBOLS_0, 4, 16, 16, 0, 0x0000, 0x0006, + charactersSYMBOLS_0, bitmapSYMBOLS_0) ] diff --git a/speculos/mcu/nbgl.py b/speculos/mcu/nbgl.py index 88e7a722..61e900dd 100644 --- a/speculos/mcu/nbgl.py +++ b/speculos/mcu/nbgl.py @@ -286,6 +286,6 @@ def hal_draw_image_rle(self, data): buffer += RLECustom.decode(1, bitmap, bpp) # Display the uncompressed image - transformation = 0 # NO_TRANSFORMATION + transformation = 0 # NO_TRANSFORMATION color_map = data[nbgl_area_t.sizeof() + len(bitmap)] # front color in case of BPP4 self.draw_image(area, bpp, transformation, buffer, color_map) diff --git a/speculos/mcu/ocr.py b/speculos/mcu/ocr.py index 8297789e..cb6dd10a 100644 --- a/speculos/mcu/ocr.py +++ b/speculos/mcu/ocr.py @@ -5,7 +5,7 @@ import os import string from dataclasses import dataclass -from typing import List, Optional, Mapping +from typing import Dict, List, Mapping from speculos.observer import TextEvent from . import bagl_font @@ -30,7 +30,13 @@ Char = str # a single character string (chars are 1-char strings in Python) -__FONT_MAP = {} +@dataclass +class BitMapChar: + char: bagl_font.FontCharacter + bitmap: bytes + + +__FONT_MAP: Dict[int, Mapping[str, BitMapChar]] = {} DISPLAY_CHARS = string.ascii_letters + string.digits + string.punctuation @@ -46,12 +52,6 @@ def wrapper(byte_string: bytes): return wrapper -@dataclass -class BitMapChar: - char: bagl_font.FontCharacter - bitmap: bytes - - def split(bits: BitVector, n: Width) -> List[BitVector]: """ Split a bit array (string of '1' and '0') @@ -125,8 +125,8 @@ class OCR: MAX_BLANK_SPACE = 12 # Font names for LNX & LNS+ (most used ones first) FONT_NAMES_NANOX_NANOSP = ["bagl_font_open_sans_regular_11px", - "bagl_font_open_sans_extrabold_11px", - "bagl_font_open_sans_light_16px"] + "bagl_font_open_sans_extrabold_11px", + "bagl_font_open_sans_light_16px"] # Font names for stax (most used ones first) FONT_NAMES_STAX = ["nbgl_font_inter_regular_24", "nbgl_font_inter_semibold_24", @@ -137,12 +137,12 @@ class OCR: "nbgl_font_hmalpha_mono_medium_32"] def __init__(self, - fonts_path:str, - model:str, - api_level:int): + fonts_path: str, + model: str, + api_level: int): self.events: List[TextEvent] = [] # To keep track of loaded JSON fonts - self.json_fonts = [] + self.json_fonts: List[Dict] = [] # By default use legacy OCR (built-in font bitmaps) self.legacy = True # Maximum space for a letter to be considered part of the same word @@ -172,7 +172,7 @@ def __init__(self, self.legacy = False else: logger = logging.getLogger("OCR") - logger.warning("WARNING: didn't find any JSON font files => "\ + logger.warning("WARNING: didn't find any JSON font files => " "OCR will not work properly!\n") def get_json_font(self, name, struct_name) -> None: @@ -185,9 +185,9 @@ def get_json_font(self, name, struct_name) -> None: # Deserialize bitmap bitmap = base64.b64decode(font_info['bitmap']) - if not struct_name in font_info: + if struct_name not in font_info: logger = logging.getLogger("OCR") - logger.warning(f"WARNING: didn't find field '{struct_name}' "\ + logger.warning(f"WARNING: didn't find field '{struct_name}' " f"in {name} => this font will be ignored!\n") return # Build BitMapChar @@ -204,7 +204,7 @@ def get_json_font(self, name, struct_name) -> None: self.json_fonts.append(font_map) @staticmethod - def find_char_from_bitmap_legacy(bitmap: BitMap) -> Optional[str]: + def find_char_from_bitmap_legacy(bitmap: BitMap) -> str: """ Find a character from a bitmap >>> font = get_font(4) @@ -228,9 +228,10 @@ def find_char_from_bitmap_legacy(bitmap: BitMap) -> Optional[str]: if char == "\x80": char = " " return char + return "" def find_bitmap_legacy(self, x: int, y: int, w: int, h: int, - bitmap: bytes) -> None: + bitmap: bytes) -> None: char = self.find_char_from_bitmap_legacy(bitmap) if char: if self.events and y <= self.events[-1].y: @@ -240,7 +241,7 @@ def find_bitmap_legacy(self, x: int, y: int, w: int, h: int, # or if there is a new line self.events.append(TextEvent(char, x, y, w, h)) - def find_char_from_bitmap(self, bitmap: BitMap) -> Optional[str]: + def find_char_from_bitmap(self, bitmap: BitMap) -> str: """ Parse loaded JSON fonts and compare font bitmaps with the one provided """ @@ -254,8 +255,9 @@ def find_char_from_bitmap(self, bitmap: BitMap) -> Optional[str]: if char == "\x80": char = " " return char + return "" - def store_char_in_last_event(self, x: int, y: int, w: int, h:int, char:str) -> None: + def store_char_in_last_event(self, x: int, y: int, w: int, h: int, char: str) -> None: """ Add current character to last event """ diff --git a/speculos/mcu/rle_custom.py b/speculos/mcu/rle_custom.py index 44ced561..f98892d6 100755 --- a/speculos/mcu/rle_custom.py +++ b/speculos/mcu/rle_custom.py @@ -8,6 +8,7 @@ import argparse import sys + # ----------------------------------------------------------------------------- # Regular RLE encoding # ----------------------------------------------------------------------------- @@ -299,6 +300,7 @@ def get_encoded_size(data): """ return len(data) + # ----------------------------------------------------------------------------- # Custom RLE encoding: pack repeat count & value into 1 byte # ----------------------------------------------------------------------------- @@ -370,6 +372,7 @@ def decode_pass2(self, data): return pairs + # ----------------------------------------------------------------------------- # Custom RLE encoding: pack repeat count & value into 1 byte + # - white handling @@ -474,6 +477,7 @@ def decode_pass2(self, data): return pairs + # ----------------------------------------------------------------------------- # Custom RLE encoding: pack repeat count & value into 1 byte + # - white handling @@ -559,7 +563,7 @@ def encode_pass2(pairs, max_count=64): if count > 6: # Special case: if count = 8 then do 5+3 if count == 8: - count = 5 # to allow storing next 3 singles!! + count = 5 # to allow storing next 3 singles!! else: count = 6 # Do we have at least 3 singles? @@ -578,13 +582,13 @@ def encode_pass2(pairs, max_count=64): index += 1 count -= 1 while count > 0: - byte = single_output[index] # No need to mask + byte = single_output[index] # No need to mask index += 1 count -= 1 byte <<= 4 # Do we have an other quartet? if count > 0: - byte |= single_output[index] # No need to mask + byte |= single_output[index] # No need to mask index += 1 count -= 1 # Store the quartet(s) @@ -667,6 +671,7 @@ def decode_pass2(self, data): return pairs + # ----------------------------------------------------------------------------- # Custom RLE encoding: pack repeat count & value into 1 byte # ----------------------------------------------------------------------------- @@ -736,6 +741,7 @@ def decode_pass2(self, data): return pairs + # ----------------------------------------------------------------------------- # Custom RLE encoding: pack repeat count & value into 1 byte # ----------------------------------------------------------------------------- @@ -772,7 +778,7 @@ def encode_pass2(self, pairs, max_count=64): infos = [] index = 0 if self.bpp == 1: - #threshold = 7 + # threshold = 7 threshold = 2 else: threshold = 3 @@ -884,11 +890,12 @@ def get_encoded_size(self, data): pixels_size += 1 sys.stdout.write(f"Nb pixels: {total_pixels}\n") - sys.stdout.write(f"sizes: cmd={cmd_size}, count={count_size}"\ + sys.stdout.write(f"sizes: cmd={cmd_size}, count={count_size}" f", data={pixels_size}\n") return cmd_size + count_size + pixels_size + # ----------------------------------------------------------------------------- # Custom RLE encoding: pack repeat count & value into 1 byte # ----------------------------------------------------------------------------- @@ -988,6 +995,7 @@ def decode_pass2(self, data): return pairs + # ----------------------------------------------------------------------------- # Custom RLE encoding: pack repeat count & value into 1 byte # ----------------------------------------------------------------------------- @@ -1091,6 +1099,7 @@ def decode_pass2(self, data): return pairs + # ----------------------------------------------------------------------------- # Entry point for easy RLE encoding/decoding # ----------------------------------------------------------------------------- @@ -1151,6 +1160,7 @@ def decode(cls, method, encoded_data, bpp, verbose=False): return decoded + # ----------------------------------------------------------------------------- # Program entry point: # ----------------------------------------------------------------------------- @@ -1161,7 +1171,7 @@ def main(args): """ Main method. """ - #ascii 0x0040 (88 bytes) + # ascii 0x0040 (88 bytes) data = bytes([ 0x00, 0x7F, 0xE0, 0x00, 0x1F, 0xFF, 0x00, 0x07, 0xC0, 0x38, 0x00, 0xF0, 0x01, 0x80, 0x1E, 0x00, @@ -1178,7 +1188,7 @@ def main(args): with RLECustomA(args.bpp, args.verbose) as rle: compressed = rle.encode(data) encoded_size = rle.get_encoded_size(compressed) - sys.stdout.write(f"Encoded size: {encoded_size} bytes "\ + sys.stdout.write(f"Encoded size: {encoded_size} bytes " f"(instead of {len(data)})\n") # No need to check if decoding is fine, already done when encoding @@ -1197,7 +1207,7 @@ def main(args): parser.add_argument( "-v", "--verbose", - action = 'store_true', + action='store_true', help="Add verbosity to output ('%(default)s' by default)") # Call main function: diff --git a/speculos/mcu/seproxyhal.py b/speculos/mcu/seproxyhal.py index e8c5e80c..59561d5e 100644 --- a/speculos/mcu/seproxyhal.py +++ b/speculos/mcu/seproxyhal.py @@ -435,6 +435,7 @@ def can_read(self, screen: DisplayNotifier): screen.display.gl.hal_draw_image(data) elif tag == SephTag.NBGL_DRAW_IMAGE_RLE: + assert isinstance(screen.display.gl, NBGL) self.ocr.analyze_bitmap(data) screen.display.gl.hal_draw_image_rle(data)