diff --git a/Makefile b/Makefile index c7f5395e74..939edffcc0 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,7 @@ help: ## show this help ## style commands: PY_FILES = $(shell find . -type f -name '*.py' | sed 'sO^\./OO' | grep -f ./tools/style.py.include | grep -v -f ./tools/style.py.exclude ) common/protob/pb2py +PY_FILES_LIMITED = $(shell find . -type f -name '*.py' | sed 'sO^\./OO' | grep -f ./tools/style.py.include | grep -v -f ./tools/style.py.exclude | grep -v -f ./tools/style.py.typecheck.exclude ) common/protob/pb2py C_FILES = $(shell find . -type f -name '*.[ch]' | grep -f ./tools/style.c.include | grep -v -f ./tools/style.c.exclude ) @@ -22,7 +23,9 @@ pystyle_check: ## run code style check on application sources and tests @echo [TYPECHECK] @make -C core typecheck @echo [FLAKE8] - @flake8 $(PY_FILES) + @flake8 $(PY_FILES_LIMITED) + @echo [FLAKE8 - limited] + @flake8 --extend-ignore=ANN $(PY_FILES) @echo [ISORT] @isort --check-only $(PY_FILES) @echo [BLACK] @@ -45,7 +48,9 @@ pystyle: ## apply code style on application sources and tests @echo [TYPECHECK] @make -C core typecheck @echo [FLAKE8] - @flake8 $(PY_FILES) + @flake8 $(PY_FILES_LIMITED) + @echo [FLAKE8 - limited] + @flake8 --extend-ignore=ANN $(PY_FILES) @echo [PYLINT] @pylint $(PY_FILES) @echo [PYTHON] diff --git a/core/tools/alloc.py b/core/tools/alloc.py index 32ccc79729..6e120b97ec 100755 --- a/core/tools/alloc.py +++ b/core/tools/alloc.py @@ -5,14 +5,14 @@ from pathlib import Path from types import SimpleNamespace from typing import TYPE_CHECKING, Dict, Protocol, TextIO -# for python37 support, is not present in typing there -from typing_extensions import TypedDict - import click from dominate import document -from dominate.tags import * +from dominate.tags import a, h3, meta, style, table, tbody, td, th, thead, tr from dominate.util import raw +# for python37 support, is not present in typing there +from typing_extensions import TypedDict + HERE = Path(__file__).resolve().parent diff --git a/core/tools/analyze-memory-dump.py b/core/tools/analyze-memory-dump.py index 97a13a703c..4ee0bb015c 100755 --- a/core/tools/analyze-memory-dump.py +++ b/core/tools/analyze-memory-dump.py @@ -2,9 +2,9 @@ import json import sys - if len(sys.argv) < 2: - print("""\ + print( + """\ USAGE: ./analyze-memory-dump.py somefile.json [memorymap.html] Where "somefile.json" was produced by using `trezor.utils.mem_dump("somefile.json")` @@ -25,8 +25,8 @@ actually care about. Modules are nothing but a link to a globals dict. The dict must be examined separately. Generators and closures are painful :( -""") - +""" + ) with open(sys.argv[1]) as f: @@ -64,7 +64,7 @@ def is_ignored_ptr(ptr): if isinstance(ptr, str): ptr = int(ptr, 16) - return not (min_ptr <= ptr < max_ptr) + return not min_ptr <= ptr < max_ptr def deref_or_shortval(maybe_ptr): @@ -204,7 +204,7 @@ pixels_per_line = len( pixelsize = bytes_per_block bytes_per_line = bytes_per_block * pixels_per_line maxline = ((max_ptr - min_ptr) & ~(bytes_per_line - 1)) + (bytes_per_line * 2) -pixelmap = [None] * 2*(maxline // pixelsize) +pixelmap = [None] * 2 * (maxline // pixelsize) def pixel_index(ptrval): diff --git a/core/tools/bld_update.py b/core/tools/bld_update.py index 1ed6a3ea9f..bf25b12165 100644 --- a/core/tools/bld_update.py +++ b/core/tools/bld_update.py @@ -1,12 +1,13 @@ #!/usr/bin/env python3 -import time -from pathlib import Path import sys +import time import zlib +from pathlib import Path import click import serial + def _compress(data: bytes) -> bytes: """ Compress data with zlib at max compression, raw deflate. @@ -14,14 +15,15 @@ def _compress(data: bytes) -> bytes: compressor = zlib.compressobj(level=9, wbits=-10) return compressor.compress(data) + compressor.flush() + def send_cmd(ser, cmd, expect_ok=True): """Send a line, read response, and abort on CLI_ERROR.""" ser.write((cmd + "\r\n").encode()) # Give the device a moment to process time.sleep(0.05) - resp = ser.readline().decode(errors='ignore').strip() + resp = ser.readline().decode(errors="ignore").strip() while resp.startswith("#") or len(resp) == 0: - resp = ser.readline().decode(errors='ignore').strip() + resp = ser.readline().decode(errors="ignore").strip() click.echo(f"> {cmd}") click.echo(f"< {resp}") if expect_ok and not resp.startswith("OK"): @@ -29,6 +31,7 @@ def send_cmd(ser, cmd, expect_ok=True): sys.exit(1) return resp + def upload_bootloader(port, bin_path, chunk_size): # Read binary file data = Path(bin_path).read_bytes() @@ -38,7 +41,9 @@ def upload_bootloader(port, bin_path, chunk_size): # Compress the data comp_data = _compress(data) comp_size = len(comp_data) - click.echo(f"Compressed to {comp_size} bytes ({comp_size*100//orig_size}% of original)") + click.echo( + f"Compressed to {comp_size} bytes ({comp_size * 100 // orig_size}% of original)" + ) # Open USB-VCP port ser = serial.Serial(port, timeout=2) @@ -52,7 +57,7 @@ def upload_bootloader(port, bin_path, chunk_size): # 2) Stream compressed chunks offset = 0 while offset < comp_size: - chunk = comp_data[offset:offset+chunk_size] + chunk = comp_data[offset : offset + chunk_size] hexstr = chunk.hex() send_cmd(ser, f"bootloader-update chunk {hexstr}") offset += len(chunk) @@ -63,11 +68,21 @@ def upload_bootloader(port, bin_path, chunk_size): send_cmd(ser, "bootloader-update end") click.echo("Bootloader upload complete.") + @click.command(context_settings={"help_option_names": ["-h", "--help"]}) @click.argument("port", metavar="") -@click.argument("binary", metavar="", type=click.Path(exists=True, dir_okay=False)) -@click.option("--chunk-size", "-c", default=512, show_default=True, - help="Max bytes per chunk (in compressed form)") +@click.argument( + "binary", + metavar="", + type=click.Path(exists=True, dir_okay=False), +) +@click.option( + "--chunk-size", + "-c", + default=512, + show_default=True, + help="Max bytes per chunk (in compressed form)", +) def main(port, binary, chunk_size): """ Upload a (compressed) bootloader image via USB-VCP CLI. @@ -84,5 +99,6 @@ def main(port, binary, chunk_size): click.echo("Interrupted by user.", err=True) sys.exit(1) + if __name__ == "__main__": main() diff --git a/core/tools/build_icons.py b/core/tools/build_icons.py index 8c2b3f0dbc..65548bc4ef 100755 --- a/core/tools/build_icons.py +++ b/core/tools/build_icons.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 -from pathlib import Path import sys +from pathlib import Path import click from PIL import Image diff --git a/core/tools/codegen/gen_cert_bundle.py b/core/tools/codegen/gen_cert_bundle.py index 9c3c33a3b4..60bbd893ae 100755 --- a/core/tools/codegen/gen_cert_bundle.py +++ b/core/tools/codegen/gen_cert_bundle.py @@ -2,20 +2,19 @@ from base64 import b64decode from hashlib import sha256 -import requests +import requests REPO = "certifi/python-certifi" def fetch_certdata(): - r = requests.get("https://api.github.com/repos/%s/git/refs/heads/master" % REPO) + r = requests.get(f"https://api.github.com/repos/{REPO}/git/refs/heads/master") assert r.status_code == 200 commithash = r.json()["object"]["sha"] r = requests.get( - "https://raw.githubusercontent.com/%s/%s/certifi/cacert.pem" - % (REPO, commithash) + f"https://raw.githubusercontent.com/{REPO}/{commithash}/certifi/cacert.pem" ) assert r.status_code == 200 certdata = r.text @@ -52,23 +51,22 @@ def process_certdata(data): def main(): commithash, certdata = fetch_certdata() - print("# fetched from https://github.com/%s" % REPO) - print("# commit %s" % commithash) + print(f"# fetched from https://github.com/{REPO}") + print(f"# commit {commithash}") certs = process_certdata(certdata) size = sum([len(x) for x in certs.values()]) print( - "# certs: %d | digests size: %d | total size: %d" - % (len(certs), len(certs) * 32, size) + f"# certs: {len(certs)} | digests size: {len(certs) * 32} | total size: {size}" ) print("cert_bundle = [") for k, v in certs.items(): h = sha256(v) - print(" # %s" % k) - print(" # %s" % h.hexdigest()) - print(" %s," % h.digest()) + print(f" # {k}") + print(f" # {h.hexdigest()}" % h.hexdigest()) + print(f" {h.digest()},") print("]") diff --git a/core/tools/codegen/gen_font.py b/core/tools/codegen/gen_font.py index 18e3179736..0210627150 100755 --- a/core/tools/codegen/gen_font.py +++ b/core/tools/codegen/gen_font.py @@ -4,17 +4,17 @@ from __future__ import annotations +import json import unicodedata from dataclasses import dataclass from pathlib import Path + import click -import json # pip install freetype-py import freetype -from mako.template import Template - from foreign_chars import all_languages +from mako.template import Template def _normalize(s: str) -> str: @@ -177,12 +177,12 @@ class Glyph: else: raise ValueError(f"Negative bearingX for character '{c}'") bearingY = metrics.horiBearingY // 64 - assert advance >= 0 and advance <= 255 - assert bearingX >= 0 and bearingX <= 255 + assert 0 <= advance <= 255 + assert 0 <= bearingX <= 255 if bearingY < 0: # HACK print(f"normalizing bearingY {bearingY} for '{c}'") bearingY = 0 - assert bearingY >= 0 and bearingY <= 255 + assert 0 <= bearingY <= 255 buf = list(bitmap.buffer) # discard non-space pixels on the left side diff --git a/core/tools/codegen/gen_keys.py b/core/tools/codegen/gen_keys.py index 8cec1cf365..2d0e45c54d 100755 --- a/core/tools/codegen/gen_keys.py +++ b/core/tools/codegen/gen_keys.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import binascii + from trezorlib import _ed25519 diff --git a/core/tools/codegen/gen_loader.py b/core/tools/codegen/gen_loader.py index 44225fc64a..1531b41280 100755 --- a/core/tools/codegen/gen_loader.py +++ b/core/tools/codegen/gen_loader.py @@ -8,31 +8,33 @@ import math def gen_loader(model, outer, inner): with open(f"loader_{model}.h", "wt") as f: f.write("// clang-format off\n") - f.write("static const int img_loader_size = %d;\n" % outer) - f.write("static const uint16_t img_loader[%d][%d] = {\n" % (outer, outer)) + f.write(f"static const int img_loader_size = {outer};\n" % outer) + f.write(f"static const uint16_t img_loader[{outer}][{outer}] = {{\n") for y in range(outer): f.write(" {") for x in range(outer): d = math.sqrt((outer - 1 - x) ** 2 + (outer - 1 - y) ** 2) c = {} for i in [5, 15]: - if (inner - 0.5 <= d) and (d <= inner + 0.5): + if inner - 0.5 <= d <= inner + 0.5: c[i] = 15 * (d - inner + 0.5) - elif (inner + 0.5 <= d) and (d <= inner + 1.5): + elif inner + 0.5 <= d <= inner + 1.5: c[i] = 15 - elif (inner + 1.5 <= d) and (d <= inner + 2.5): + elif inner + 1.5 <= d <= inner + 2.5: c[i] = 15 if i == 15 else 15 - (15 - i) * (d - inner - 1.5) - elif (outer - 1.5 <= d) and (d <= outer - 0.5): + elif outer - 1.5 <= d <= outer - 0.5: c[i] = i - i * (d - outer + 1.5) - elif (inner + 2.5 < d) and (d < outer - 1.5): + elif inner + 2.5 < d < outer - 1.5: c[i] = i else: c[i] = 0 # clamp (should not be needed) c[i] = max(0, min(int(c[i]), 15)) - a = int(math.atan2((outer - 1 - x), (outer - 1 - y)) * 2 * 249 / math.pi) + a = int( + math.atan2((outer - 1 - x), (outer - 1 - y)) * 2 * 249 / math.pi + ) v = (a << 8) | (c[15] << 4) | c[5] - f.write("%d," % v) + f.write(f"{v},") f.write("},\n") f.write("};\n") @@ -40,4 +42,3 @@ def gen_loader(model, outer, inner): if __name__ == "__main__": gen_loader("T", 60, 42) gen_loader("R", 20, 14) - diff --git a/core/tools/codegen/get_trezor_keys.py b/core/tools/codegen/get_trezor_keys.py index 31c40fef1f..6f7a8d0cdc 100755 --- a/core/tools/codegen/get_trezor_keys.py +++ b/core/tools/codegen/get_trezor_keys.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import binascii + from trezorlib.client import TrezorClient from trezorlib.transport_hid import HidTransport @@ -11,7 +12,7 @@ else: raise Exception("No Trezor found") for i in [0, 1, 2]: - path = "m/10018'/%d'" % i + path = f"m/10018'/{i}'" pk = t.get_public_node( t.expand_path(path), ecdsa_curve_name="ed25519", show_display=True ) diff --git a/core/tools/coverage-annotate.py b/core/tools/coverage-annotate.py index 8d86dc0e9a..bb13c0f0b0 100755 --- a/core/tools/coverage-annotate.py +++ b/core/tools/coverage-annotate.py @@ -1,10 +1,8 @@ #!/usr/bin/env python3 import json import sys - from collections import defaultdict - # Aggregate hits from all coverage JSON files data = defaultdict(lambda: defaultdict(int)) for file_path in sys.argv[1:]: diff --git a/core/tools/coverage-collect.py b/core/tools/coverage-collect.py index aeee7d57a3..cc84964f1f 100755 --- a/core/tools/coverage-collect.py +++ b/core/tools/coverage-collect.py @@ -1,8 +1,9 @@ #!/usr/bin/env python3 -import coverage import json import sys +import coverage + result_filename, *coverage_filenames = sys.argv[1:] data = coverage.CoverageData(result_filename) diff --git a/core/tools/hid-bridge/hid_interface.py b/core/tools/hid-bridge/hid_interface.py index 0f1c696f52..cbe55dca48 100644 --- a/core/tools/hid-bridge/hid_interface.py +++ b/core/tools/hid-bridge/hid_interface.py @@ -76,15 +76,13 @@ class HIDInterface: def write_data(self, data): buf = uhid.create_input2_event(data) self.__uhid_write(buf) - logger.log_uhid_event( - "UHID_INPUT2", f"data=0x{data.hex()} size={len(data)}" - ) + logger.log_uhid_event("UHID_INPUT2", f"data=0x{data.hex()} size={len(data)}") logger.log_hid_packet("DEVICE_OUTPUT", f"0x{data.hex()}") def process_event(self): ev_type, request = uhid.parse_event(self.__uhid_read(uhid.EVENT_LENGTH)) if ev_type == uhid.EVENT_TYPE_START: - dev_flags, = request + (dev_flags,) = request logger.log_uhid_event("UHID_START", f"dev_flags=0b{dev_flags:08b}") elif ev_type == uhid.EVENT_TYPE_STOP: logger.log_uhid_event("UHID_STOP") @@ -105,3 +103,4 @@ class HIDInterface: "UNKNOWN_EVENT", f"ev_type={ev_type} request=0x{request.hex()}", ) + return None diff --git a/core/tools/hid-bridge/logger.py b/core/tools/hid-bridge/logger.py index d6d6732d47..b8a71ae3b4 100644 --- a/core/tools/hid-bridge/logger.py +++ b/core/tools/hid-bridge/logger.py @@ -9,7 +9,7 @@ def __get_timestamp(): def __log_message(message): - if log_timestamps == True: + if log_timestamps: print(f"{__get_timestamp()}\t{message}") else: print(message) diff --git a/core/tools/jpg_to_h.py b/core/tools/jpg_to_h.py index 6499242255..f353f3d1f5 100644 --- a/core/tools/jpg_to_h.py +++ b/core/tools/jpg_to_h.py @@ -2,9 +2,10 @@ Creates a header file containing image data. """ -import click import pathlib +import click + h_file_template = """\ // clang-format off unsigned char {name}_jpg[] = {content}; @@ -40,7 +41,13 @@ def convert(infile): image_bytes = image_bytes.rstrip(", \n") with open(h_file_name, "w") as f: - f.write(h_file_template.format(name=img_name, content=content.format(image_bytes=image_bytes), length=len(image_data))) + f.write( + h_file_template.format( + name=img_name, + content=content.format(image_bytes=image_bytes), + length=len(image_data), + ) + ) if __name__ == "__main__": diff --git a/core/tools/make_cmakelists.py b/core/tools/make_cmakelists.py index 951aa2cc9e..ba0ef27699 100644 --- a/core/tools/make_cmakelists.py +++ b/core/tools/make_cmakelists.py @@ -4,7 +4,7 @@ import argparse def gen(sources, dirs, defs): target = "CMakeLists.txt" - with open(target, 'w') as f: + with open(target, "w") as f: f.write("cmake_minimum_required(VERSION 3.20)\n") f.write("project(core)\n") @@ -16,20 +16,20 @@ def gen(sources, dirs, defs): f.write("add_definitions(\n") for d in defs: - f.write(f' -D{d}\n') + f.write(f" -D{d}\n") f.write(")\n") f.write("\n") f.write("\n") for d in dirs: - f.write(f'include_directories({d})\n') + f.write(f"include_directories({d})\n") f.write("\n") f.write("\n") f.write("add_executable(core\n") for s in sources: - f.write(f' {s}\n') + f.write(f" {s}\n") f.write(")\n") f.write("\n") diff --git a/core/tools/nrf_update.py b/core/tools/nrf_update.py index 79531fb6ad..92b433817c 100644 --- a/core/tools/nrf_update.py +++ b/core/tools/nrf_update.py @@ -1,11 +1,12 @@ #!/usr/bin/env python3 +import sys import time from pathlib import Path -import sys import click import serial + def send_cmd(ser, cmd, expect_ok=True): """Send a line, read response, and abort on non-OK.""" ser.write((cmd + "\r\n").encode()) @@ -22,6 +23,7 @@ def send_cmd(ser, cmd, expect_ok=True): sys.exit(1) return resp + def upload_nrf(port, bin_path, chunk_size): # Read binary file data = Path(bin_path).read_bytes() @@ -40,7 +42,7 @@ def upload_nrf(port, bin_path, chunk_size): # 2) Stream chunks offset = 0 while offset < total: - chunk = data[offset:offset + chunk_size] + chunk = data[offset : offset + chunk_size] hexstr = chunk.hex() send_cmd(ser, f"nrf-update chunk {hexstr}") offset += len(chunk) @@ -51,11 +53,15 @@ def upload_nrf(port, bin_path, chunk_size): send_cmd(ser, "nrf-update end") click.echo("nRF update complete.") + @click.command(context_settings={"help_option_names": ["-h", "--help"]}) @click.argument("port", metavar="") -@click.argument("binary", metavar="", type=click.Path(exists=True, dir_okay=False)) -@click.option("--chunk-size", "-c", default=512, show_default=True, - help="Max bytes per chunk") +@click.argument( + "binary", metavar="", type=click.Path(exists=True, dir_okay=False) +) +@click.option( + "--chunk-size", "-c", default=512, show_default=True, help="Max bytes per chunk" +) def main(port, binary, chunk_size): """ Upload an nRF firmware image via USB-VCP CLI. @@ -72,5 +78,6 @@ def main(port, binary, chunk_size): click.echo("Interrupted by user.", err=True) sys.exit(1) + if __name__ == "__main__": main() diff --git a/core/tools/provision_device.py b/core/tools/provision_device.py index bd98c7d315..4b37d76639 100644 --- a/core/tools/provision_device.py +++ b/core/tools/provision_device.py @@ -2,14 +2,14 @@ from __future__ import annotations import os import secrets +import shlex from dataclasses import dataclass from typing import Any -from typing_extensions import Self import click import requests import serial -import shlex +from typing_extensions import Self SERVER_TOKEN = "" SERVER_URL = "http://localhost:8000/provision" @@ -114,9 +114,9 @@ class Connection: if res.startswith(b"ERROR"): error_args = res[len(b"ERROR ") :].decode() parts = shlex.split(error_args) - error_text = parts[0] # error code + error_text = parts[0] # error code if len(parts) > 1: - error_text = parts[1] # error description + error_text = parts[1] # error description raise ProdtestException(error_text) elif res.startswith(b"OK"): res_arg = res[len(b"OK ") :] @@ -129,6 +129,7 @@ class Connection: elif not res.startswith(b"#"): raise ProdtestException("Unexpected response: " + res.decode()) + def provision_request( device: DeviceInfo, url: str, model: str, verify: bool = True ) -> ProvisioningResult: @@ -140,7 +141,7 @@ def provision_request( "cert": device.device_cert.hex(), "model": model, } - resp = requests.post(url + '/provision', json=request, verify=verify) + resp = requests.post(url + "/provision", json=request, verify=verify) if resp.status_code == 400: print("Server returned error:", resp.text) resp.raise_for_status() diff --git a/core/tools/size/apps.py b/core/tools/size/apps.py index 47d3e335cd..085dad5285 100755 --- a/core/tools/size/apps.py +++ b/core/tools/size/apps.py @@ -9,8 +9,7 @@ import re import sys from pathlib import Path - -from binsize import BinarySize, StatisticsPlugin, DataRow +from binsize import BinarySize, DataRow, StatisticsPlugin HERE = Path(__file__).parent CORE_DIR = HERE.parent.parent diff --git a/core/tools/size/compare_master.py b/core/tools/size/compare_master.py index 5022ab4fb8..0e3126232f 100755 --- a/core/tools/size/compare_master.py +++ b/core/tools/size/compare_master.py @@ -18,10 +18,9 @@ from io import BytesIO from pathlib import Path from zipfile import ZipFile -import requests import click - -from binsize import BinarySize, get_sections_sizes, show_binaries_diff, set_root_dir +import requests +from binsize import BinarySize, get_sections_sizes, set_root_dir, show_binaries_diff HERE = Path(__file__).parent CORE_DIR = HERE.parent.parent diff --git a/core/tools/snippets/change_icon_format.py b/core/tools/snippets/change_icon_format.py index 4100bb72fd..5d020783b2 100644 --- a/core/tools/snippets/change_icon_format.py +++ b/core/tools/snippets/change_icon_format.py @@ -12,31 +12,31 @@ CORE_DIR = HERE.parent.parent def process_line(infile: TextIO, outfile: BinaryIO) -> None: line = infile.readline() - data = [x.strip().lower() for x in line.split(',')] + data = [x.strip().lower() for x in line.split(",")] for c in data: if len(c) == 4: outfile.write(bytes((int(c, 16),))) def header_to_toif(path: str | Path) -> str: - with open(path, "r") as infile, open('tmp.toif', "wb") as outfile: + with open(path, "r") as infile, open("tmp.toif", "wb") as outfile: infile.readline() name_line = infile.readline() name = name_line.split(" ")[3].split("[")[0] infile.readline() - magic_line = infile.readline().split(',')[3] + magic_line = infile.readline().split(",")[3] outfile.write(bytes((0x54,))) - outfile.write(bytes((0x4f,))) + outfile.write(bytes((0x4F,))) outfile.write(bytes((0x49,))) if "g" in magic_line: - outfile.write(bytes((ord('g'),))) + outfile.write(bytes((ord("g"),))) elif "G" in magic_line: - outfile.write(bytes((ord('G'),))) + outfile.write(bytes((ord("G"),))) elif "f" in magic_line: - outfile.write(bytes((ord('f'),))) + outfile.write(bytes((ord("f"),))) elif "F" in magic_line: - outfile.write(bytes((ord('F'),))) + outfile.write(bytes((ord("F"),))) else: print(magic_line) raise Exception("Unknown format") @@ -52,53 +52,71 @@ def header_to_toif(path: str | Path) -> str: def toif_to_header(path: str | Path, name: str) -> None: - with open('tmp_c.toif', "rb") as infile, open(path, "w") as outfile: + with open("tmp_c.toif", "rb") as infile, open(path, "w") as outfile: b = infile.read(4) outfile.write("// clang-format off\n") - outfile.write(f'static const uint8_t {name}[] = {{\n',) - outfile.write(" // magic\n",) - if b[3] == ord('f'): - outfile.write(" 'T', 'O', 'I', 'f',\n",) - elif b[3] == ord('F'): - outfile.write(" 'T', 'O', 'I', 'F',\n",) - elif b[3] == ord('g'): - outfile.write(" 'T', 'O', 'I', 'g',\n",) - elif b[3] == ord('G'): - outfile.write(" 'T', 'O', 'I', 'G',\n",) + outfile.write( + f"static const uint8_t {name}[] = {{\n", + ) + outfile.write( + " // magic\n", + ) + if b[3] == ord("f"): + outfile.write( + " 'T', 'O', 'I', 'f',\n", + ) + elif b[3] == ord("F"): + outfile.write( + " 'T', 'O', 'I', 'F',\n", + ) + elif b[3] == ord("g"): + outfile.write( + " 'T', 'O', 'I', 'g',\n", + ) + elif b[3] == ord("G"): + outfile.write( + " 'T', 'O', 'I', 'G',\n", + ) else: raise Exception("Unknown format") - outfile.write(" // width (16-bit), height (16-bit)\n",) + outfile.write( + " // width (16-bit), height (16-bit)\n", + ) outfile.write(" ") for i in range(4): hex_data = infile.read(1).hex() - outfile.write(f'0x{hex_data},') + outfile.write(f"0x{hex_data},") if i != 3: - outfile.write(' ') + outfile.write(" ") outfile.write("\n") - outfile.write(" // compressed data length (32-bit)\n",) + outfile.write( + " // compressed data length (32-bit)\n", + ) outfile.write(" ") for i in range(4): hex_data = infile.read(1).hex() - outfile.write(f'0x{hex_data},') + outfile.write(f"0x{hex_data},") if i != 3: - outfile.write(' ') + outfile.write(" ") outfile.write("\n") - outfile.write(" // compressed data\n",) + outfile.write( + " // compressed data\n", + ) outfile.write(" ") hex_data = infile.read(1).hex() first = True while hex_data: if not first: - outfile.write(' ') + outfile.write(" ") first = False - outfile.write(f'0x{hex_data},') + outfile.write(f"0x{hex_data},") hex_data = infile.read(1).hex() outfile.write("\n};\n") - _byte = infile.read(1) + infile.read(1) def reformat_c_icon(path: str | Path) -> None: diff --git a/core/tools/snippets/decombine.py b/core/tools/snippets/decombine.py index 66fd9f2481..ab2411d1b6 100644 --- a/core/tools/snippets/decombine.py +++ b/core/tools/snippets/decombine.py @@ -1,6 +1,7 @@ import io import sys from pathlib import Path + from trezorlib._internal import firmware_headers from trezorlib.firmware.core import FirmwareHeader, HeaderType diff --git a/core/tools/translations/validate_strings.py b/core/tools/translations/validate_strings.py index 92008de25d..59ce79e924 100644 --- a/core/tools/translations/validate_strings.py +++ b/core/tools/translations/validate_strings.py @@ -1,8 +1,8 @@ from __future__ import annotations import json -from dataclasses import dataclass import sys +from dataclasses import dataclass from helpers import HERE, TRANSLATIONS_DIR diff --git a/core/tools/trezor_core_tools/bootloader_hashes.py b/core/tools/trezor_core_tools/bootloader_hashes.py index dad0f2ac7a..e4a958f771 100755 --- a/core/tools/trezor_core_tools/bootloader_hashes.py +++ b/core/tools/trezor_core_tools/bootloader_hashes.py @@ -1,15 +1,14 @@ #!/usr/bin/env python3 +from hashlib import blake2s +from pathlib import Path + import click -from pathlib import Path -from hashlib import blake2s - from trezorlib.firmware.core import FirmwareImage, Model -from .layout_parser import find_value from .common import MODELS_DIR - +from .layout_parser import find_value TEMPLATE = """\ #ifndef BOOTLOADER_HASHES_H diff --git a/core/tools/trezor_core_tools/common.py b/core/tools/trezor_core_tools/common.py index e896e79eb3..40ba364701 100644 --- a/core/tools/trezor_core_tools/common.py +++ b/core/tools/trezor_core_tools/common.py @@ -7,15 +7,16 @@ CORE = HERE.parent.parent MODELS_DIR = CORE / "embed" / "models" + def get_layout_for_model(model: str, secmon: bool) -> Path: if secmon: - return MODELS_DIR / model / f"memory_secmon.h" + return MODELS_DIR / model / "memory_secmon.h" else: - return MODELS_DIR / model / f"memory.h" + return MODELS_DIR / model / "memory.h" + def get_linkerscript_for_model(model: str, secmon: bool) -> Path: if secmon: - return MODELS_DIR / model / f"memory_secmon.ld" + return MODELS_DIR / model / "memory_secmon.ld" else: - return MODELS_DIR / model / f"memory.ld" - + return MODELS_DIR / model / "memory.ld" diff --git a/core/tools/trezor_core_tools/headertool.py b/core/tools/trezor_core_tools/headertool.py index 61600da359..1302b40f05 100755 --- a/core/tools/trezor_core_tools/headertool.py +++ b/core/tools/trezor_core_tools/headertool.py @@ -1,11 +1,11 @@ #!/usr/bin/env python3 +from typing import List, Tuple + import click from trezorlib import cosi, firmware from trezorlib._internal import firmware_headers -from typing import List, Sequence, Tuple - # =========================== signing ========================= @@ -47,6 +47,11 @@ def do_replace_vendorheader(fw, vh_file) -> None: fw.vendor_header = vh +def no_echo(*args, **kwargs): + """A no-op function to replace click.echo when quiet mode is enabled.""" + pass + + @click.command() @click.option("-n", "--dry-run", is_flag=True, help="Do not save changes.") @click.option("-h", "--rehash", is_flag=True, help="Force recalculate hashes.") @@ -132,7 +137,7 @@ def cli( traceback.print_exc() magic = firmware_data[:4] raise click.ClickException( - "Could not parse file (magic bytes: {!r})".format(magic) + f"Could not parse file (magic bytes: {magic})" ) from e digest = fw.digest() @@ -141,7 +146,7 @@ def cli( return if quiet: - echo = lambda *args, **kwargs: None + echo = no_echo else: echo = click.echo diff --git a/core/tools/trezor_core_tools/layout_parser.py b/core/tools/trezor_core_tools/layout_parser.py index 3544f4d8b3..203b4c1448 100644 --- a/core/tools/trezor_core_tools/layout_parser.py +++ b/core/tools/trezor_core_tools/layout_parser.py @@ -1,14 +1,13 @@ #!/usr/bin/env python3 from __future__ import annotations +import ast import re import click -import ast from .common import get_layout_for_model - # the following regular expression matches a thing looking like those examples: # #define HEADER_START 0x123456 # #define HEADER_START (1 * 2 * 3) // comment @@ -48,7 +47,7 @@ def find_value(model: str, name: str, secmon: bool) -> int: @click.argument("model") @click.argument("name") @click.option("--secmon", is_flag=True) -def main(model: str, name: str, secmon:bool) -> None: +def main(model: str, name: str, secmon: bool) -> None: try: print(find_value(model, name, secmon)) except ValueError as e: diff --git a/core/tools/trezor_core_tools/lsgen.py b/core/tools/trezor_core_tools/lsgen.py index 9acdabbb76..5c91709d98 100644 --- a/core/tools/trezor_core_tools/lsgen.py +++ b/core/tools/trezor_core_tools/lsgen.py @@ -1,22 +1,23 @@ #!/usr/bin/env python3 from __future__ import annotations -import click import itertools -from .common import get_linkerscript_for_model, get_layout_for_model, MODELS_DIR -from .layout_parser import find_all_values +import click +from .common import MODELS_DIR, get_layout_for_model, get_linkerscript_for_model +from .layout_parser import find_all_values FILE_HEADER = """/* Auto-generated file, do not edit.*/ """ + def create_linker_script(model: str, cmse: bool) -> str: content = FILE_HEADER defines = find_all_values(model, cmse) for name, value in defines.items(): - content += f"{name} = {hex(value)};\n" + content += f"{name} = {hex(value)};\n" return content @@ -31,7 +32,7 @@ def main(check: bool) -> None: path = get_layout_for_model(model.name, split) if not path.exists(): - continue + continue path = get_linkerscript_for_model(model.name, split) print(f"Processing {path}") @@ -45,5 +46,6 @@ def main(check: bool) -> None: else: path.write_text(new_content) + if __name__ == "__main__": main() diff --git a/tools/build_solana_templates.py b/tools/build_solana_templates.py index dc726fa200..4c0e78b1b6 100755 --- a/tools/build_solana_templates.py +++ b/tools/build_solana_templates.py @@ -7,7 +7,7 @@ from pathlib import Path import click from mako.template import Template -from munch import munchify, Munch +from munch import Munch, munchify HERE = Path(__file__).parent ROOT = HERE.parent.resolve() diff --git a/tools/bump-version.py b/tools/bump-version.py index 2f92ce4c75..9caaaeddc4 100755 --- a/tools/bump-version.py +++ b/tools/bump-version.py @@ -1,8 +1,8 @@ #!/usr/bin/env python3 -from pathlib import Path import re import subprocess +from pathlib import Path import click @@ -40,7 +40,7 @@ def bump_python(filename, new_version): def hex_lit(version): - return r'"\x{:02X}"'.format(int(version)) + return rf'"\x{int(version):02X}"' @click.command() diff --git a/tools/changelog.py b/tools/changelog.py index bc8e44c324..6c91d3228f 100755 --- a/tools/changelog.py +++ b/tools/changelog.py @@ -1,14 +1,13 @@ #!/usr/bin/env python3 import datetime -from pathlib import Path import re import subprocess +from pathlib import Path +from typing import Iterator import click -from typing import Iterator - LINK_RE = re.compile(r"\[#(\d+)\]") ISSUE_URL = "https://github.com/trezor/trezor-firmware/pull/{issue}" @@ -265,7 +264,7 @@ def generate(project, version, date, check, only_models): if only_models: generate_filtered(project, changelog) - return 0 + return args = ["towncrier", "build", "--yes", "--version", version, "--date", date] if check: diff --git a/tools/firmware_hash.py b/tools/firmware_hash.py index b38b7131bb..96ca316470 100755 --- a/tools/firmware_hash.py +++ b/tools/firmware_hash.py @@ -19,7 +19,7 @@ elif len(sys.argv) == 2: filenames = (FILE_T1, FILE_T2) else: print(f"Usage: {sys.argv[0]} HEX_CHALLENGE [FILE]...") - print(f" HEX_CHALLENGE: a 0-32 byte challenge in hexadecimal") + print(" HEX_CHALLENGE: a 0-32 byte challenge in hexadecimal") exit(1) diff --git a/tools/github_issues_to_csv.py b/tools/github_issues_to_csv.py index 015f17adb9..783f30c02a 100644 --- a/tools/github_issues_to_csv.py +++ b/tools/github_issues_to_csv.py @@ -3,11 +3,13 @@ Taken from https://gist.github.com/patrickfuller/e2ea8a94badc5b6967ef3ca0a9452a Currently writes all issues that have some Weight. """ + import argparse import csv -import requests import os.path +import requests + token = None path = os.path.dirname(os.path.realpath(__file__)) @@ -49,7 +51,6 @@ def write_issues(r, csvout): if not weight: continue labels = ", ".join(labels) - date = issue["created_at"].split("T")[0] milestone = issue["milestone"]["title"] if issue["milestone"] else "" assignee = issue["assignee"]["login"] if issue["assignee"] else "" diff --git a/tools/print-rust-stack-sizes.py b/tools/print-rust-stack-sizes.py index 0e2406477a..f91a9ecba9 100755 --- a/tools/print-rust-stack-sizes.py +++ b/tools/print-rust-stack-sizes.py @@ -4,9 +4,8 @@ import subprocess from pathlib import Path import click - -from elftools.construct import Struct, ULInt32, GreedyRange from elftools.common.construct_utils import ULEB128 +from elftools.construct import GreedyRange, Struct, ULInt32 from elftools.elf.elffile import ELFFile SYMBOL_TYPES = ("t", "w") # text, weak diff --git a/tools/pyright_tool.py b/tools/pyright_tool.py index 535fecb248..364616d298 100755 --- a/tools/pyright_tool.py +++ b/tools/pyright_tool.py @@ -49,13 +49,13 @@ from pathlib import Path from typing import Dict # for python38 support, must be used in type aliases from typing import List # for python38 support, must be used in type aliases from typing import TYPE_CHECKING, Any, Iterator + +import click from typing_extensions import ( # for python37 support, is not present in typing there Final, TypedDict, ) -import click - if TYPE_CHECKING: LineIgnores = List["LineIgnore"] @@ -542,7 +542,7 @@ class PyrightTool: ignore_statements = self.get_ignore_statements(line) if not ignore_statements: self.inconsistencies.append( - f"There is an empty `{self.IGNORE_PATTERN}` in {file}:{index+1}" + f"There is an empty `{self.IGNORE_PATTERN}` in {file}:{index + 1}" ) else: ignores.append(LineIgnore(index, ignore_statements)) diff --git a/tools/snippets/eth_defs_unpack.py b/tools/snippets/eth_defs_unpack.py index ea96c48128..ee0dfd7f27 100755 --- a/tools/snippets/eth_defs_unpack.py +++ b/tools/snippets/eth_defs_unpack.py @@ -17,11 +17,12 @@ # If not, see . from __future__ import annotations -import click -import requests import zipfile from pathlib import Path +import click +import requests + from trezorlib import definitions, merkle_tree ZIP_FILENAME = "definitions-sparse.zip" diff --git a/tools/snippets/font_multiplier.py b/tools/snippets/font_multiplier.py index 4aba4ccc71..5cbb8e4adc 100644 --- a/tools/snippets/font_multiplier.py +++ b/tools/snippets/font_multiplier.py @@ -4,9 +4,9 @@ from __future__ import annotations -from typing_extensions import Literal from typing import Tuple +from typing_extensions import Literal Bit = Literal[0, 1] Point = Tuple[int, int] diff --git a/tools/snippets/monero_unused_functions.py b/tools/snippets/monero_unused_functions.py index bd63582895..559433b0aa 100644 --- a/tools/snippets/monero_unused_functions.py +++ b/tools/snippets/monero_unused_functions.py @@ -68,11 +68,10 @@ def check_usage_of_functions(func_mapping: Dict[str, List[str]]) -> None: is_used_mappings[func_name] = {"mapping": mapping, "is_used": False} # Check if any of the mapping names is used - and mark it as used if so - for func_name in is_used_mappings: - for mapping in is_used_mappings[func_name]["mapping"]: - is_there = _is_used(mapping) - if is_there: - is_used_mappings[func_name]["is_used"] = True + for func_name, info in is_used_mappings.items(): + for m in info["mapping"]: + if _is_used(m): + info["is_used"] = True break # Find unused functions and generate a report diff --git a/tools/snippets/recalc_optiga_for_emulator.py b/tools/snippets/recalc_optiga_for_emulator.py index 95345781b8..6791799239 100644 --- a/tools/snippets/recalc_optiga_for_emulator.py +++ b/tools/snippets/recalc_optiga_for_emulator.py @@ -1,12 +1,12 @@ import sys from pathlib import Path -from pyasn1.codec.der.encoder import encode -from pyasn1.codec.der.decoder import decode -from pyasn1.type.univ import BitString -from pyasn1_modules import rfc2459 from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import ec +from pyasn1.codec.der.decoder import decode +from pyasn1.codec.der.encoder import encode +from pyasn1.type.univ import BitString +from pyasn1_modules import rfc2459 def load_certificate(data: bytes): diff --git a/tools/snippets/unify_test_files.py b/tools/snippets/unify_test_files.py index 15a05cf78d..8fbc5ac99d 100644 --- a/tools/snippets/unify_test_files.py +++ b/tools/snippets/unify_test_files.py @@ -37,6 +37,7 @@ Usage: - specifying FILES_TO_MODIFY - call the script with possible flags - see `python unify_test_files.py --help` """ + import json import os import re @@ -92,7 +93,7 @@ class FileUnifier: else: self.translations = {} print( - f"{len(self.translations)} translations available (path/address and address/path)\n{80*'*'}" + f"{len(self.translations)} translations available (path/address and address/path)\n{80 * '*'}" ) # For statistical purposes diff --git a/tools/style.py.exclude b/tools/style.py.exclude index bbbdabc878..7c835bee74 100644 --- a/tools/style.py.exclude +++ b/tools/style.py.exclude @@ -2,3 +2,4 @@ ^legacy/firmware/protob/options_pb2\.py ^legacy/firmware/protob/messages_nem_pb2\.py ^legacy/vendor +^tools/automatic_battery_tester/.venv/ diff --git a/tools/style.py.include b/tools/style.py.include index 94a9cd61fd..9552d9b082 100644 --- a/tools/style.py.include +++ b/tools/style.py.include @@ -2,8 +2,10 @@ ^core/src/ ^core/site_scons/ ^core/tests/ +^core/tools/ ^crypto/ ^legacy/ ^storage/ +^tools/ ^tests/ ^ci/ diff --git a/tools/style.py.typecheck.exclude b/tools/style.py.typecheck.exclude new file mode 100644 index 0000000000..2924ef6030 --- /dev/null +++ b/tools/style.py.typecheck.exclude @@ -0,0 +1,2 @@ +^core/tools/ +^tools/