chore(core, tools, common): improve type annotation, resolve issues
What changed, and why it matters
This is a large cleanup commit that improves Python type annotations and fixes minor code-quality issues across build tools, helper scripts, and test utilities. It does not change any security-critical firmware behavior, cryptographic operations, or device-facing code. There is no indication this commit fixes a security vulnerability.
No security action required. Treat as routine code hygiene / type-annotation cleanup. Reviewers may optionally verify that the `to_bytes(2, 'big')` change in `generate_tropic_model_config.py` and the `required=True` addition in `hash_signer.py` do not break intended tooling workflows.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit is a broad refactoring across ~82 files in the Trezor firmware repository. Changes include: adding type hints, replacing deprecated typing imports (Dict/List) with built-in generics, adding assert guards for potentially-None values, fixing a byte-order argument in to_bytes(2, 'big'), adding a missing required=True to a click option, and updating API calls (e.g., btc.sign_tx now uses a session object). The title and message explicitly describe it as ‘improve type annotation, resolve issues’ with ‘[no changelog]’. No runtime security logic in the firmware itself is modified.
Changed components
common/protob/check.pycommon/tools/coin_info.pycommon/tools/cointool.pycore/site_scons/models/*core/site_scons/tools.pycore/tools/*python/src/trezorlib/_internal/firmware_headers.pytools/automatic_battery_tester/*tools/build_solana_templates.pytools/bump-version.pytools/changelog.pytools/check_docs_summary.pytools/github_issues_to_csv.pytools/print-rust-stack-sizes.pytools/snippets/*tools/trezor-pylint-plugin/trezor_pylint_plugin.pyInspect captured patch +590 / −423
diff --git a/common/protob/check.py b/common/protob/check.py
index 01c239d6..88f1fbbe 100755
--- a/common/protob/check.py
+++ b/common/protob/check.py
@@ -10,19 +10,22 @@ MYDIR = os.path.dirname(__file__)
EXPECTED_PREFIX_RE = re.compile(r"messages-(\w+)(?:-.*)?\.proto")
+WITHOUT_PREFIX = [
+ "Bitcoin",
+ "Bootloader",
+ "Common",
+ "Crypto",
+ "Definitions",
+ "Management",
+]
# Checking all protobuf files for their `enum` and `message` declarations
# and making sure their names start with expected prefix
for fn in sorted(glob(os.path.join(MYDIR, "messages-*.proto"))):
with open(fn, "rt") as f:
- prefix = EXPECTED_PREFIX_RE.search(fn).group(1).capitalize()
- if prefix in (
- "Bitcoin",
- "Bootloader",
- "Common",
- "Crypto",
- "Definitions",
- "Management",
- ):
+ filename = EXPECTED_PREFIX_RE.search(fn)
+ assert filename
+ prefix = filename.group(1).capitalize()
+ if prefix in WITHOUT_PREFIX:
continue
if prefix == "Nem":
prefix = "NEM"
diff --git a/common/tools/coin_info.py b/common/tools/coin_info.py
index 79581e2f..bfa753e6 100755
--- a/common/tools/coin_info.py
+++ b/common/tools/coin_info.py
@@ -6,14 +6,7 @@ import logging
import re
from collections import OrderedDict, defaultdict
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 Any, Callable, Iterable, Iterator, cast
-
-from typing_extensions import ( # for python37 support, is not present in typing there
- Literal,
- TypedDict,
-)
+from typing import Any, Callable, Iterable, Iterator, Literal, TypedDict, cast
try:
import requests
@@ -31,9 +24,9 @@ class SupportItemVersion(TypedDict):
unsupported: dict[str, str]
-SupportData = Dict[str, SupportItemVersion]
-SupportInfoItem = Dict[str, Literal[False] | str]
-SupportInfo = Dict[str, SupportInfoItem]
+SupportData = dict[str, SupportItemVersion]
+SupportInfoItem = dict[str, Literal[False] | str]
+SupportInfo = dict[str, SupportInfoItem]
class Coin(TypedDict):
@@ -107,8 +100,8 @@ class Coin(TypedDict):
bitcore: list[str]
-Coins = List[Coin]
-CoinBuckets = Dict[str, Coins]
+Coins = list[Coin]
+CoinBuckets = dict[str, Coins]
class FidoApp(TypedDict):
@@ -124,7 +117,7 @@ class FidoApp(TypedDict):
icon: str
-FidoApps = List[FidoApp]
+FidoApps = list[FidoApp]
def load_json(*path: str | Path) -> Any:
@@ -144,7 +137,7 @@ def get_btc_testnet_status(name: str) -> bool:
# ====== CoinsInfo ======
-class CoinsInfo(Dict[str, Coins]):
+class CoinsInfo(dict[str, Coins]):
"""Collection of information about all known kinds of coins.
It contains the following lists:
diff --git a/common/tools/cointool.py b/common/tools/cointool.py
index eb03ca06..54dbbf96 100755
--- a/common/tools/cointool.py
+++ b/common/tools/cointool.py
@@ -1,4 +1,5 @@
#!/usr/bin/env python3
+# pyright: reportArgumentType=false, reportAttributeAccessIssue=false, reportGeneralTypeIssues=false
from __future__ import annotations
import datetime
diff --git a/core/site_scons/models/D001/__init__.py b/core/site_scons/models/D001/__init__.py
index f668fdda..2b4a38da 100644
--- a/core/site_scons/models/D001/__init__.py
+++ b/core/site_scons/models/D001/__init__.py
@@ -6,9 +6,9 @@ from .discovery import configure
def configure_board(
- revision: Optional[int | str],
+ revision: Optional[str],
features_wanted: list[str],
- env: dict, # type: ignore
+ env: dict,
defines: list[str | tuple[str, str]],
sources: list[str],
paths: list[str],
diff --git a/core/site_scons/models/D001/discovery.py b/core/site_scons/models/D001/discovery.py
index ef147666..4d1ba80a 100644
--- a/core/site_scons/models/D001/discovery.py
+++ b/core/site_scons/models/D001/discovery.py
@@ -22,13 +22,14 @@ def configure(
env, features_wanted, defines, sources, paths
)
- env.get("ENV")[
- "CPU_ASFLAGS"
- ] = "-mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16"
- env.get("ENV")[
- "CPU_CCFLAGS"
- ] = "-mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -mtune=cortex-m4 "
- env.get("ENV")["RUST_TARGET"] = "thumbv7em-none-eabihf"
+ ENV = env.get("ENV")
+ assert ENV
+
+ ENV["CPU_ASFLAGS"] = "-mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16"
+ ENV["CPU_CCFLAGS"] = (
+ "-mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -mtune=cortex-m4 "
+ )
+ ENV["RUST_TARGET"] = "thumbv7em-none-eabihf"
defines += [
mcu,
diff --git a/core/site_scons/models/D002/__init__.py b/core/site_scons/models/D002/__init__.py
index 05f0f286..10160244 100644
--- a/core/site_scons/models/D002/__init__.py
+++ b/core/site_scons/models/D002/__init__.py
@@ -6,9 +6,9 @@ from .discovery2 import configure
def configure_board(
- revision: Optional[int | str],
+ revision: Optional[str],
features_wanted: list[str],
- env: dict, # type: ignore
+ env: dict,
defines: list[str | tuple[str, str]],
sources: list[str],
paths: list[str],
diff --git a/core/site_scons/models/D002/discovery2.py b/core/site_scons/models/D002/discovery2.py
index 74d4d5b4..e58b3984 100644
--- a/core/site_scons/models/D002/discovery2.py
+++ b/core/site_scons/models/D002/discovery2.py
@@ -24,16 +24,17 @@ def configure(
env, features_wanted, defines, sources, paths
)
- env.get("ENV")[
- "CPU_ASFLAGS"
- ] = "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 "
- env.get("ENV")[
- "CPU_CCFLAGS"
- ] = "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 -mtune=cortex-m33 "
- env.get("ENV")["RUST_TARGET"] = "thumbv8m.main-none-eabihf"
+ ENV = env.get("ENV")
+ assert ENV
+
+ ENV["CPU_ASFLAGS"] = "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 "
+ ENV["CPU_CCFLAGS"] = (
+ "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 -mtune=cortex-m33 "
+ )
+ ENV["RUST_TARGET"] = "thumbv8m.main-none-eabihf"
if "secure_domain" in features_wanted:
- env.get("ENV")["CPU_CCFLAGS"] += "-mcmse "
+ ENV["CPU_CCFLAGS"] += "-mcmse "
if "secmon_layout" in features_wanted:
defines += [("USE_SECMON_LAYOUT", "1")]
@@ -112,7 +113,7 @@ def configure(
"USE_OEM_KEYS_CHECK=1",
]
- env.get("ENV")["LINKER_SCRIPT"] = linker_script
- env.get("ENV")["MEMORY_LAYOUT"] = memory_layout
+ ENV["LINKER_SCRIPT"] = linker_script
+ ENV["MEMORY_LAYOUT"] = memory_layout
return features_available
diff --git a/core/site_scons/models/T2B1/__init__.py b/core/site_scons/models/T2B1/__init__.py
index 10f3ec07..163c38ec 100644
--- a/core/site_scons/models/T2B1/__init__.py
+++ b/core/site_scons/models/T2B1/__init__.py
@@ -1,14 +1,15 @@
from __future__ import annotations
+from types import ModuleType
from typing import Optional
from . import emulator, trezor_r_v10
def configure_board(
- revision: Optional[int | str],
+ revision: Optional[str],
features_wanted: list[str],
- env: dict, # type: ignore
+ env: dict,
defines: list[str | tuple[str, str]],
sources: list[str],
paths: list[str],
@@ -17,12 +18,12 @@ def configure_board(
defines += (("VERSIONS_HEADER", '"T2B1/versions.h"'),)
# Set default revision if None
- revision = revision or 10
+ revision = revision or "10"
# Mapping of revisions to their respective configurations
- revision_map = {
+ revision_map: dict[str, ModuleType] = {
"emulator": emulator,
- 10: trezor_r_v10,
+ "10": trezor_r_v10,
}
module = revision_map.get(revision)
diff --git a/core/site_scons/models/T2B1/trezor_r_v10.py b/core/site_scons/models/T2B1/trezor_r_v10.py
index e0834e30..1590f9f5 100644
--- a/core/site_scons/models/T2B1/trezor_r_v10.py
+++ b/core/site_scons/models/T2B1/trezor_r_v10.py
@@ -31,13 +31,14 @@ def configure(
env, features_wanted, defines, sources, paths
)
- env.get("ENV")[
- "CPU_ASFLAGS"
- ] = "-mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16"
- env.get("ENV")[
- "CPU_CCFLAGS"
- ] = "-mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -mtune=cortex-m4 "
- env.get("ENV")["RUST_TARGET"] = "thumbv7em-none-eabihf"
+ ENV = env.get("ENV")
+ assert ENV
+
+ ENV["CPU_ASFLAGS"] = "-mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16"
+ ENV["CPU_CCFLAGS"] = (
+ "-mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -mtune=cortex-m4 "
+ )
+ ENV["RUST_TARGET"] = "thumbv7em-none-eabihf"
defines += [
mcu,
diff --git a/core/site_scons/models/T2T1/__init__.py b/core/site_scons/models/T2T1/__init__.py
index 91d57aa1..166c9aca 100644
--- a/core/site_scons/models/T2T1/__init__.py
+++ b/core/site_scons/models/T2T1/__init__.py
@@ -7,9 +7,9 @@ from .trezor_t import configure
def configure_board(
- revision: Optional[int | str],
+ revision: Optional[str],
features_wanted: list[str],
- env: dict, # type: ignore
+ env: dict,
defines: list[str | tuple[str, str]],
sources: list[str],
paths: list[str],
diff --git a/core/site_scons/models/T2T1/trezor_t.py b/core/site_scons/models/T2T1/trezor_t.py
index 5eec1654..dd784584 100644
--- a/core/site_scons/models/T2T1/trezor_t.py
+++ b/core/site_scons/models/T2T1/trezor_t.py
@@ -30,13 +30,14 @@ def configure(
env, features_wanted, defines, sources, paths
)
- env.get("ENV")[
- "CPU_ASFLAGS"
- ] = "-mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16"
- env.get("ENV")[
- "CPU_CCFLAGS"
- ] = "-mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -mtune=cortex-m4 "
- env.get("ENV")["RUST_TARGET"] = "thumbv7em-none-eabihf"
+ ENV = env.get("ENV")
+ assert ENV
+
+ ENV["CPU_ASFLAGS"] = "-mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16"
+ ENV["CPU_CCFLAGS"] = (
+ "-mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -mtune=cortex-m4 "
+ )
+ ENV["RUST_TARGET"] = "thumbv7em-none-eabihf"
defines += [
mcu,
diff --git a/core/site_scons/models/T3B1/__init__.py b/core/site_scons/models/T3B1/__init__.py
index 72b1aa2a..f721e43f 100644
--- a/core/site_scons/models/T3B1/__init__.py
+++ b/core/site_scons/models/T3B1/__init__.py
@@ -1,14 +1,15 @@
from __future__ import annotations
+from types import ModuleType
from typing import Optional
from . import emulator, trezor_t3b1_revB
def configure_board(
- revision: Optional[int | str],
+ revision: Optional[str],
features_wanted: list[str],
- env: dict, # type: ignore
+ env: dict,
defines: list[str | tuple[str, str]],
sources: list[str],
paths: list[str],
@@ -20,7 +21,7 @@ def configure_board(
revision = revision or "B"
# Mapping of revisions to their respective configurations
- revision_map = {
+ revision_map: dict[str, ModuleType] = {
"emulator": emulator,
"B": trezor_t3b1_revB,
}
diff --git a/core/site_scons/models/T3B1/trezor_t3b1_revB.py b/core/site_scons/models/T3B1/trezor_t3b1_revB.py
index af711076..e63315f3 100644
--- a/core/site_scons/models/T3B1/trezor_t3b1_revB.py
+++ b/core/site_scons/models/T3B1/trezor_t3b1_revB.py
@@ -33,13 +33,14 @@ def configure(
env, features_wanted, defines, sources, paths
)
- env.get("ENV")[
- "CPU_ASFLAGS"
- ] = "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 "
- env.get("ENV")[
- "CPU_CCFLAGS"
- ] = "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 -mtune=cortex-m33 -mcmse "
- env.get("ENV")["RUST_TARGET"] = "thumbv8m.main-none-eabihf"
+ ENV = env.get("ENV")
+ assert ENV
+
+ ENV["CPU_ASFLAGS"] = "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 "
+ ENV["CPU_CCFLAGS"] = (
+ "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 -mtune=cortex-m33 -mcmse "
+ )
+ ENV["RUST_TARGET"] = "thumbv8m.main-none-eabihf"
defines += [
mcu,
@@ -101,9 +102,9 @@ def configure(
("USE_PVD", "1"),
]
- env.get("ENV")["TREZOR_BOARD"] = board
- env.get("ENV")["MCU_TYPE"] = mcu
- env.get("ENV")["LINKER_SCRIPT"] = linker_script
- env.get("ENV")["MEMORY_LAYOUT"] = memory_layout
+ ENV["TREZOR_BOARD"] = board
+ ENV["MCU_TYPE"] = mcu
+ ENV["LINKER_SCRIPT"] = linker_script
+ ENV["MEMORY_LAYOUT"] = memory_layout
return features_available
diff --git a/core/site_scons/models/T3T1/__init__.py b/core/site_scons/models/T3T1/__init__.py
index 628853f7..a4f5e6c0 100644
--- a/core/site_scons/models/T3T1/__init__.py
+++ b/core/site_scons/models/T3T1/__init__.py
@@ -1,14 +1,15 @@
from __future__ import annotations
+from types import ModuleType
from typing import Optional
from . import emulator, trezor_t3t1_revE
def configure_board(
- revision: Optional[int | str],
+ revision: Optional[str],
features_wanted: list[str],
- env: dict, # type: ignore
+ env: dict,
defines: list[str | tuple[str, str]],
sources: list[str],
paths: list[str],
@@ -20,7 +21,7 @@ def configure_board(
revision = revision or "E"
# Mapping of revisions to their respective configurations
- revision_map = {
+ revision_map: dict[str, ModuleType] = {
"emulator": emulator,
"E": trezor_t3t1_revE,
}
diff --git a/core/site_scons/models/T3T1/trezor_t3t1_revE.py b/core/site_scons/models/T3T1/trezor_t3t1_revE.py
index bdedeb2f..839a6214 100644
--- a/core/site_scons/models/T3T1/trezor_t3t1_revE.py
+++ b/core/site_scons/models/T3T1/trezor_t3t1_revE.py
@@ -35,13 +35,14 @@ def configure(
env, features_wanted, defines, sources, paths
)
- env.get("ENV")[
- "CPU_ASFLAGS"
- ] = "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 "
- env.get("ENV")[
- "CPU_CCFLAGS"
- ] = "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 -mtune=cortex-m33 -mcmse "
- env.get("ENV")["RUST_TARGET"] = "thumbv8m.main-none-eabihf"
+ ENV = env.get("ENV")
+ assert ENV
+
+ ENV["CPU_ASFLAGS"] = "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 "
+ ENV["CPU_CCFLAGS"] = (
+ "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 -mtune=cortex-m33 -mcmse "
+ )
+ ENV["RUST_TARGET"] = "thumbv8m.main-none-eabihf"
defines += [
mcu,
@@ -134,9 +135,9 @@ def configure(
("USE_PVD", "1"),
]
- env.get("ENV")["TREZOR_BOARD"] = board
- env.get("ENV")["MCU_TYPE"] = mcu
- env.get("ENV")["LINKER_SCRIPT"] = linker_script
- env.get("ENV")["MEMORY_LAYOUT"] = memory_layout
+ ENV["TREZOR_BOARD"] = board
+ ENV["MCU_TYPE"] = mcu
+ ENV["LINKER_SCRIPT"] = linker_script
+ ENV["MEMORY_LAYOUT"] = memory_layout
return features_available
diff --git a/core/site_scons/models/T3W1/__init__.py b/core/site_scons/models/T3W1/__init__.py
index b41fa170..0122e845 100644
--- a/core/site_scons/models/T3W1/__init__.py
+++ b/core/site_scons/models/T3W1/__init__.py
@@ -1,14 +1,15 @@
from __future__ import annotations
+from types import ModuleType
from typing import Optional
from . import emulator, trezor_t3w1_revA, trezor_t3w1_revB, trezor_t3w1_revC
def configure_board(
- revision: Optional[int | str],
+ revision: Optional[str],
features_wanted: list[str],
- env: dict, # type: ignore
+ env: dict,
defines: list[str | tuple[str, str]],
sources: list[str],
paths: list[str],
@@ -20,7 +21,7 @@ def configure_board(
revision = revision or "C"
# Mapping of revisions to their respective configurations
- revision_map = {
+ revision_map: dict[str, ModuleType] = {
"emulator": emulator,
"A": trezor_t3w1_revA,
"B": trezor_t3w1_revB,
diff --git a/core/site_scons/models/T3W1/trezor_t3w1_revA.py b/core/site_scons/models/T3W1/trezor_t3w1_revA.py
index da7b385b..f18b4677 100644
--- a/core/site_scons/models/T3W1/trezor_t3w1_revA.py
+++ b/core/site_scons/models/T3W1/trezor_t3w1_revA.py
@@ -24,16 +24,17 @@ def configure(
env, features_wanted, defines, sources, paths
)
- env.get("ENV")[
- "CPU_ASFLAGS"
- ] = "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 "
- env.get("ENV")[
- "CPU_CCFLAGS"
- ] = "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 -mtune=cortex-m33 "
- env.get("ENV")["RUST_TARGET"] = "thumbv8m.main-none-eabihf"
+ ENV = env.get("ENV")
+ assert ENV
+
+ ENV["CPU_ASFLAGS"] = "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 "
+ ENV["CPU_CCFLAGS"] = (
+ "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 -mtune=cortex-m33 "
+ )
+ ENV["RUST_TARGET"] = "thumbv8m.main-none-eabihf"
if "secure_domain" in features_wanted:
- env.get("ENV")["CPU_CCFLAGS"] += "-mcmse "
+ ENV["CPU_CCFLAGS"] += "-mcmse "
if "secmon_layout" in features_wanted:
defines += [("USE_SECMON_LAYOUT", "1")]
@@ -311,7 +312,7 @@ def configure(
defines += [("USE_SERIAL_NUMBER", "1")]
features_available.append("serial_number")
- env.get("ENV")["LINKER_SCRIPT"] = linker_script
- env.get("ENV")["MEMORY_LAYOUT"] = memory_layout
+ ENV["LINKER_SCRIPT"] = linker_script
+ ENV["MEMORY_LAYOUT"] = memory_layout
return features_available
diff --git a/core/site_scons/models/T3W1/trezor_t3w1_revB.py b/core/site_scons/models/T3W1/trezor_t3w1_revB.py
index 12cfe7c9..1970beba 100644
--- a/core/site_scons/models/T3W1/trezor_t3w1_revB.py
+++ b/core/site_scons/models/T3W1/trezor_t3w1_revB.py
@@ -24,16 +24,17 @@ def configure(
env, features_wanted, defines, sources, paths
)
- env.get("ENV")[
- "CPU_ASFLAGS"
- ] = "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 "
- env.get("ENV")[
- "CPU_CCFLAGS"
- ] = "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 -mtune=cortex-m33 "
- env.get("ENV")["RUST_TARGET"] = "thumbv8m.main-none-eabihf"
+ ENV = env.get("ENV")
+ assert ENV
+
+ ENV["CPU_ASFLAGS"] = "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 "
+ ENV["CPU_CCFLAGS"] = (
+ "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 -mtune=cortex-m33 "
+ )
+ ENV["RUST_TARGET"] = "thumbv8m.main-none-eabihf"
if "secure_domain" in features_wanted:
- env.get("ENV")["CPU_CCFLAGS"] += "-mcmse "
+ ENV["CPU_CCFLAGS"] += "-mcmse "
if "secmon_layout" in features_wanted:
defines += [("USE_SECMON_LAYOUT", "1")]
@@ -319,7 +320,7 @@ def configure(
defines += [("USE_SERIAL_NUMBER", "1")]
features_available.append("serial_number")
- env.get("ENV")["LINKER_SCRIPT"] = linker_script
- env.get("ENV")["MEMORY_LAYOUT"] = memory_layout
+ ENV["LINKER_SCRIPT"] = linker_script
+ ENV["MEMORY_LAYOUT"] = memory_layout
return features_available
diff --git a/core/site_scons/models/T3W1/trezor_t3w1_revC.py b/core/site_scons/models/T3W1/trezor_t3w1_revC.py
index 2665918e..dd0bfea5 100644
--- a/core/site_scons/models/T3W1/trezor_t3w1_revC.py
+++ b/core/site_scons/models/T3W1/trezor_t3w1_revC.py
@@ -24,16 +24,17 @@ def configure(
env, features_wanted, defines, sources, paths
)
- env.get("ENV")[
- "CPU_ASFLAGS"
- ] = "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 "
- env.get("ENV")[
- "CPU_CCFLAGS"
- ] = "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 -mtune=cortex-m33 "
- env.get("ENV")["RUST_TARGET"] = "thumbv8m.main-none-eabihf"
+ ENV = env.get("ENV")
+ assert ENV
+
+ ENV["CPU_ASFLAGS"] = "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 "
+ ENV["CPU_CCFLAGS"] = (
+ "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 -mtune=cortex-m33 "
+ )
+ ENV["RUST_TARGET"] = "thumbv8m.main-none-eabihf"
if "secure_domain" in features_wanted:
- env.get("ENV")["CPU_CCFLAGS"] += "-mcmse "
+ ENV["CPU_CCFLAGS"] += "-mcmse "
if "secmon_layout" in features_wanted:
defines += [("USE_SECMON_LAYOUT", "1")]
@@ -318,7 +319,7 @@ def configure(
defines += [("USE_SERIAL_NUMBER", "1")]
features_available.append("serial_number")
- env.get("ENV")["LINKER_SCRIPT"] = linker_script
- env.get("ENV")["MEMORY_LAYOUT"] = memory_layout
+ ENV["LINKER_SCRIPT"] = linker_script
+ ENV["MEMORY_LAYOUT"] = memory_layout
return features_available
diff --git a/core/site_scons/models/__init__.py b/core/site_scons/models/__init__.py
index bbb56bd4..8243ce11 100644
--- a/core/site_scons/models/__init__.py
+++ b/core/site_scons/models/__init__.py
@@ -10,9 +10,9 @@ def get_hw_model_as_number(hw_model: str) -> int:
def configure_board(
model: str,
- revision: Optional[str | int],
+ revision: Optional[str],
features_wanted: list[str],
- env: dict, # type: ignore
+ env: dict,
defines: list[str | tuple[str, str]],
sources: list[str],
paths: list[str],
@@ -37,7 +37,7 @@ def _configure_common_modules(
defines: list[str | tuple[str, str]],
sources: list[str],
paths: list[str],
-) -> list[str]:
+) -> None:
if "kernel_mode" in features_wanted:
defines += [("KERNEL_MODE", "1")]
diff --git a/core/site_scons/tools.py b/core/site_scons/tools.py
index 95461bcb..5d9b6962 100644
--- a/core/site_scons/tools.py
+++ b/core/site_scons/tools.py
@@ -52,7 +52,7 @@ def get_git_modified() -> bool:
def get_defs_for_cmake(defs: list[str | tuple[str, str]]) -> list[str]:
result: list[str] = []
for d in defs:
- if type(d) is tuple:
+ if isinstance(d, tuple):
val = d[1].replace('"', '\\"').replace("(", "\\(").replace(")", "\\)")
result.append(f'{d[0]}="{val}"')
else:
diff --git a/core/tools/alloc.py b/core/tools/alloc.py
index aa901169..f3e11a2a 100755
--- a/core/tools/alloc.py
+++ b/core/tools/alloc.py
@@ -1,4 +1,6 @@
#!/usr/bin/env python3
+# pyright: reportAssignmentType=false, reportAttributeAccessIssue=false, reportGeneralTypeIssues=false
+
from __future__ import annotations
from pathlib import Path
@@ -52,8 +54,8 @@ def parse_alloc_data(
@click.pass_context
@click.option("-a", "--alloc-data", type=click.File(), default="src/alloc_data.txt")
@click.option("-t", "--type", type=click.Choice(("total", "avg")), default="avg")
-def cli(ctx: click.Context, alloc_data: TextIO, type: str):
- shared_obj: SharedObject = SimpleNamespace() # type: ignore
+def cli(ctx: click.Context, alloc_data: TextIO, type: str) -> None:
+ shared_obj: SharedObject = SimpleNamespace()
shared_obj.data = parse_alloc_data(alloc_data)
shared_obj.type = type
ctx.obj = shared_obj
@@ -68,7 +70,7 @@ def _normalize_filename(filename: str) -> str:
@cli.command()
@click.pass_obj
@click.argument("filename")
-def annotate(obj: SharedObject, filename: str):
+def annotate(obj: SharedObject, filename: str) -> None:
filename = _normalize_filename(filename)
if obj.type == "total":
@@ -113,7 +115,7 @@ def _list(
@cli.command(name="list")
@click.pass_obj
@click.option("-r", "--reverse", is_flag=True)
-def list_function(obj: SharedObject, reverse: bool):
+def list_function(obj: SharedObject, reverse: bool) -> None:
if obj.type == "total":
field = "total_allocs"
@@ -161,7 +163,7 @@ def get_biggest_n_lines_for_each_file(
@cli.command()
@click.pass_obj
@click.argument("htmldir")
-def html(obj: SharedObject, htmldir: str):
+def html(obj: SharedObject, htmldir: str) -> None:
file_sums = _list(obj, "total_allocs", reverse=True)
style_grey = "color: grey"
style_red = "color: red;"
diff --git a/core/tools/analyze-memory-dump.py b/core/tools/analyze-memory-dump.py
index 4ee0bb01..d712e424 100755
--- a/core/tools/analyze-memory-dump.py
+++ b/core/tools/analyze-memory-dump.py
@@ -1,6 +1,13 @@
#!/usr/bin/env python3
+# pyright: reportAttributeAccessIssue=false, reportGeneralTypeIssues=false
+
+from __future__ import annotations
+
import json
import sys
+from typing import Any, Iterator, Optional
+
+from typing_extensions import TypeGuard
if len(sys.argv) < 2:
print(
@@ -40,15 +47,15 @@ MEMMAP = [m for m in MEMMAP if isinstance(m, dict)]
MEMORY = {}
-def is_ptr(maybe_ptr):
+def is_ptr(maybe_ptr: Any) -> TypeGuard[str]:
return isinstance(maybe_ptr, str) and maybe_ptr.startswith("0x")
-def is_gc_ptr(maybe_ptr):
+def is_gc_ptr(maybe_ptr: Any) -> bool:
return is_ptr(maybe_ptr) and maybe_ptr.startswith("0x7f")
-def ptr_or_shortval(maybe_ptr):
+def ptr_or_shortval(maybe_ptr: Any) -> str:
if is_ptr(maybe_ptr):
return maybe_ptr
else:
@@ -57,7 +64,7 @@ def ptr_or_shortval(maybe_ptr):
return maybe_ptr["shortval"]
-def is_ignored_ptr(ptr):
+def is_ignored_ptr(ptr: Any) -> bool:
if ptr == "(nil)":
return True
@@ -67,7 +74,7 @@ def is_ignored_ptr(ptr):
return not min_ptr <= ptr < max_ptr
-def deref_or_shortval(maybe_ptr):
+def deref_or_shortval(maybe_ptr: Any) -> Any:
if is_ptr(maybe_ptr) and maybe_ptr in MEMORY:
return MEMORY[maybe_ptr]
else:
@@ -75,7 +82,8 @@ def deref_or_shortval(maybe_ptr):
class Item:
- def __init__(self, item):
+
+ def __init__(self, item: Any) -> None:
self.item = item
self.backlinks = []
self.dict = {}
@@ -83,7 +91,7 @@ class Item:
self.type = item["type"]
self.ptr = item["ptr"]
- def backlinkify(self):
+ def backlinkify(self) -> None:
if "children" in self.item:
for child in self.item["children"]:
key_str = ptr_or_shortval(child["key"])
@@ -95,7 +103,7 @@ class Item:
continue
MEMORY[ptr].backlinks.append(self)
- def find_pointers(self):
+ def find_pointers(self) -> Iterator[str]:
if "children" in self.item:
for child in self.item["children"]:
if is_ptr(child["key"]):
@@ -113,15 +121,15 @@ class Item:
if is_ptr(v):
yield v
- def __getattr__(self, key):
+ def __getattr__(self, key: str) -> Any:
if key not in self.item:
raise AttributeError
return self.item[key]
- def find_modules(self):
+ def find_modules(self) -> list["Item"]:
return [it for it in self.backlinks if it.type == "module"]
- def name(self):
+ def name(self) -> Optional[str]:
if "__name__" in self.dict:
return self.dict["__name__"]
@@ -148,7 +156,7 @@ class Item:
return None
- def ptrval(self):
+ def ptrval(self) -> int:
return int(self.ptr[2:], 16)
@@ -207,7 +215,7 @@ maxline = ((max_ptr - min_ptr) & ~(bytes_per_line - 1)) + (bytes_per_line * 2)
pixelmap = [None] * 2 * (maxline // pixelsize)
-def pixel_index(ptrval):
+def pixel_index(ptrval: int) -> int:
ptridx = ptrval - min_ptr
# assert ptridx >= 0
return ptridx // pixelsize
@@ -314,7 +322,7 @@ for pixel in pixelmap:
previtem = pixel
-def text_or_ptr(s):
+def text_or_ptr(s: str) -> Any:
if s.startswith("0x7"):
sp = t.span()
sp.add(t.a(s, href=f"#{s}"))
@@ -326,7 +334,7 @@ def text_or_ptr(s):
return t.span(s)
-def dump_single_val(value):
+def dump_single_val(value: Any) -> Any:
if isinstance(value, str):
return text_or_ptr(value)
elif isinstance(value, dict):
@@ -346,7 +354,7 @@ def dump_single_val(value):
return str(value)
-def dump_dict(dl, d):
+def dump_dict(dl: Any, d: dict[str, Any]) -> None:
for key, value in d.items():
dl.add(t.dt(key))
dl.add(t.dd(dump_single_val(value)))
diff --git a/core/tools/bin_update.py b/core/tools/bin_update.py
index f8a58906..a65f49bc 100644
--- a/core/tools/bin_update.py
+++ b/core/tools/bin_update.py
@@ -15,13 +15,13 @@ UPDATE_TYPES = {
}
-def exit_interactive_mode(ser):
+def exit_interactive_mode(ser: serial.Serial) -> None:
ser.write(("." + "\r\n").encode())
time.sleep(0.1)
ser.reset_input_buffer()
-def send_cmd(ser, cmd, expect_ok=True):
+def send_cmd(ser: serial.Serial, cmd: str, expect_ok: bool = True) -> str:
"""Send a line, read response, and abort on non-OK."""
ser.write((cmd + "\r\n").encode())
# Give the device a moment to process
@@ -38,7 +38,7 @@ def send_cmd(ser, cmd, expect_ok=True):
return resp
-def upload_binary(port, bin_path, chunk_size, update_type):
+def upload_binary(port: str, bin_path: str, chunk_size: int, update_type: str) -> None:
if update_type not in UPDATE_TYPES:
raise ValueError(
f"Invalid update type. Must be one of: {', '.join(UPDATE_TYPES.keys())}"
@@ -93,7 +93,7 @@ def upload_binary(port, bin_path, chunk_size, update_type):
required=True,
help="Type of update to perform",
)
-def main(port, binary, chunk_size, type):
+def main(port: str, binary: str, chunk_size: int, type: str) -> None:
"""
Upload a firmware image via USB-VCP CLI.
diff --git a/core/tools/bld_update.py b/core/tools/bld_update.py
index 86d472a8..cfc5505f 100755
--- a/core/tools/bld_update.py
+++ b/core/tools/bld_update.py
@@ -16,13 +16,13 @@ def compress_binary(data: bytes) -> bytes:
return compressor.compress(data) + compressor.flush()
-def exit_interactive_mode(ser):
+def exit_interactive_mode(ser: serial.Serial) -> None:
ser.write(("." + "\r\n").encode())
time.sleep(0.1)
ser.reset_input_buffer()
-def send_cmd(ser, cmd, expect_ok=True):
+def send_cmd(ser: serial.Serial, cmd: str, expect_ok: bool = True) -> str:
"""Send a line, read response, and abort on CLI_ERROR."""
ser.write((cmd + "\r\n").encode())
# Give the device a moment to process
@@ -38,7 +38,7 @@ def send_cmd(ser, cmd, expect_ok=True):
return resp
-def upload_bootloader(port, bin_path, chunk_size):
+def upload_bootloader(port: str, bin_path: str, chunk_size: int) -> None:
# Read binary file
data = Path(bin_path).read_bytes()
data_size = len(data)
@@ -102,7 +102,7 @@ def upload_bootloader(port, bin_path, chunk_size):
show_default=True,
help="Max bytes per chunk (in compressed form)",
)
-def main(port, binary, chunk_size):
+def main(port: str, binary: str, chunk_size: int) -> None:
"""
Upload a bootloader image via USB-VCP CLI.
diff --git a/core/tools/bluez-emu-bridge.py b/core/tools/bluez-emu-bridge.py
index c60cb010..823b6bf0 100755
--- a/core/tools/bluez-emu-bridge.py
+++ b/core/tools/bluez-emu-bridge.py
@@ -1,4 +1,5 @@
#!/usr/bin/env python3
+# pyright: reportAttributeAccessIssue=false, reportGeneralTypeIssues=false, reportReturnType=false
"""
The purpose of this script is to create a mock D-Bus API of BlueZ, the Linux Bluetooth protocol
stack. Using environment variables you can trick programs to use this API instead of the system
@@ -41,7 +42,7 @@ LOG = logging.getLogger(__name__)
class TrezorUDP(asyncio.DatagramProtocol):
@classmethod
- async def create(cls, ip, port) -> Self:
+ async def create(cls, ip: str, port: int) -> Self:
loop = asyncio.get_running_loop()
addr = (ip, port)
return await loop.create_datagram_endpoint(
@@ -49,7 +50,7 @@ class TrezorUDP(asyncio.DatagramProtocol):
remote_addr=addr,
)
- def __init__(self, addr):
+ def __init__(self, addr: tuple[str, int]) -> None:
self.addr = addr
self.transport = None
self.queue = asyncio.Queue()
@@ -57,27 +58,27 @@ class TrezorUDP(asyncio.DatagramProtocol):
def ipport(self) -> str:
return f"{self.addr[0]}:{self.addr[1]}"
- def connection_made(self, transport: asyncio.DatagramTransport):
+ def connection_made(self, transport: asyncio.DatagramTransport) -> None:
self.transport = transport
- def connection_lost(self, exc: Exception | None):
+ def connection_lost(self, exc: Exception | None) -> None:
# Does this ever happen?
LOG.error(f"{self.ipport()} Connection lost", exc_info=exc)
- def datagram_received(self, data: bytes, addr):
+ def datagram_received(self, data: bytes, addr: tuple[str, int]) -> None:
if addr != self.addr:
LOG.error(f"{self.ipport()} Stray datagram from {addr}?")
return
self.queue.put_nowait(data)
- def error_received(self, exc: Exception | None):
+ def error_received(self, exc: Exception | None) -> None:
LOG.error(f"{self.ipport()} UDP error", exc_info=exc)
- def write(self, value: bytes):
+ def write(self, value: bytes) -> None:
assert self.transport
self.transport.sendto(value)
- def close(self):
+ def close(self) -> None:
if self.transport:
self.transport.close()
self.transport = None
@@ -85,15 +86,16 @@ class TrezorUDP(asyncio.DatagramProtocol):
class TrezorEmulator:
+
def __init__(
self,
- data_transport,
- data_protocol,
- data_read_task,
- event_transport,
- event_protocol,
- event_read_task,
- ):
+ data_transport: asyncio.DatagramTransport,
+ data_protocol: TrezorUDP,
+ data_read_task: asyncio.Task,
+ event_transport: asyncio.DatagramTransport,
+ event_protocol: TrezorUDP,
+ event_read_task: asyncio.Task,
+ ) -> None:
self._data_transport = data_transport
self.data_protocol = data_protocol
self.data_read_task = data_read_task
@@ -101,7 +103,7 @@ class TrezorEmulator:
self.event_protocol = event_protocol
self.event_read_task = event_read_task
- def close(self):
+ def close(self) -> None:
self.data_transport.close()
self.event_transport.close()
@@ -142,7 +144,7 @@ class TrezorEmulator:
return obj
-async def emulator_main(bus_address: str, emulator_port: int):
+async def emulator_main(bus_address: str, emulator_port: int) -> None:
bus = await MessageBus(bus_address=bus_address).connect()
hci0 = Adapter1(bus, "hci0")
@@ -185,11 +187,12 @@ def start_bus() -> str:
encoding="utf-8",
)
- def callback():
+ def callback() -> None:
daemon.terminate()
daemon.kill()
atexit.register(callback)
+ assert daemon.stdout is not None
address = daemon.stdout.readline().strip()
LOG.info(f"dbus-daemon listening at {address}")
parts = address.split(",")
@@ -211,7 +214,7 @@ def start_bus() -> str:
default=21328,
help="Trezor emulated BLE port to connect to.",
)
-def cli(verbose: bool, emulator_port: int, bus_address: str | None):
+def cli(verbose: bool, emulator_port: int, bus_address: str | None) -> None:
if verbose:
logging.getLogger().setLevel(logging.DEBUG)
if not bus_address:
diff --git a/core/tools/bluez_emu_bridge/adapter1.py b/core/tools/bluez_emu_bridge/adapter1.py
index ad640dca..3a09e722 100644
--- a/core/tools/bluez_emu_bridge/adapter1.py
+++ b/core/tools/bluez_emu_bridge/adapter1.py
@@ -4,7 +4,8 @@ import asyncio
import logging
import random
-from dbus_fast.service import PropertyAccess, ServiceInterface, dbus_property, method
+from dbus_fast.constants import PropertyAccess
+from dbus_fast.service import ServiceInterface, dbus_property, method
LOG = logging.getLogger(__name__)
diff --git a/core/tools/bluez_emu_bridge/device1.py b/core/tools/bluez_emu_bridge/device1.py
index 2740c4b8..7f3fa655 100644
--- a/core/tools/bluez_emu_bridge/device1.py
+++ b/core/tools/bluez_emu_bridge/device1.py
@@ -5,7 +5,8 @@ import logging
import random
from dbus_fast import DBusError, Variant
-from dbus_fast.service import PropertyAccess, ServiceInterface, dbus_property, method
+from dbus_fast.constants import PropertyAccess
+from dbus_fast.service import ServiceInterface, dbus_property, method
from trezorlib._internal.emu_ble import Command, CommandType, Event, EventType, ModeType
diff --git a/core/tools/bluez_emu_bridge/gattcharacteristic1.py b/core/tools/bluez_emu_bridge/gattcharacteristic1.py
index db07be5c..cb40d7ec 100644
--- a/core/tools/bluez_emu_bridge/gattcharacteristic1.py
+++ b/core/tools/bluez_emu_bridge/gattcharacteristic1.py
@@ -2,7 +2,8 @@
import logging
-from dbus_fast.service import PropertyAccess, ServiceInterface, dbus_property, method
+from dbus_fast.constants import PropertyAccess
+from dbus_fast.service import ServiceInterface, dbus_property, method
LOG = logging.getLogger(__name__)
diff --git a/core/tools/bluez_emu_bridge/gattservice1.py b/core/tools/bluez_emu_bridge/gattservice1.py
index bb85fae1..04d53bb0 100644
--- a/core/tools/bluez_emu_bridge/gattservice1.py
+++ b/core/tools/bluez_emu_bridge/gattservice1.py
@@ -1,6 +1,7 @@
# flake8: noqa: F722, F821
-from dbus_fast.service import PropertyAccess, ServiceInterface, dbus_property
+from dbus_fast.constants import PropertyAccess
+from dbus_fast.service import ServiceInterface, dbus_property
class GattService1(ServiceInterface):
diff --git a/core/tools/bluez_emu_bridge/message_bus.py b/core/tools/bluez_emu_bridge/message_bus.py
index 4100108a..63385b5c 100644
--- a/core/tools/bluez_emu_bridge/message_bus.py
+++ b/core/tools/bluez_emu_bridge/message_bus.py
@@ -1,4 +1,5 @@
import logging
+from typing import Any
from dbus_fast import aio
from dbus_fast.message import Message
@@ -12,7 +13,12 @@ class MessageBus(aio.MessageBus):
if self._disconnected:
return
- def get_properties_callback(interface, result, user_data, e):
+ def get_properties_callback(
+ interface: ServiceInterface,
+ result: Any,
+ user_data: Any,
+ e: Exception | None,
+ ) -> None:
if e is not None:
try:
raise e
diff --git a/core/tools/build_icons.py b/core/tools/build_icons.py
index 65548bc4..8f56ad8d 100755
--- a/core/tools/build_icons.py
+++ b/core/tools/build_icons.py
@@ -27,20 +27,20 @@ EXCLUDE = {"icon_webauthn"}
COMMON_TOOLS_PATH = ROOT / "common" / "tools"
sys.path.insert(0, str(COMMON_TOOLS_PATH))
-import coin_info
+import coin_info # type: ignore [Import "coin_info" could not be resolved]
@click.command()
@click.option("-c", "--check", is_flag=True, help="Do not write, only check.")
@click.option("-r", "--remove", is_flag=True, help="Remove unrecognized files.")
-def build_icons(check: bool, remove: bool):
+def build_icons(check: bool, remove: bool) -> None:
"""Build FIDO app icons in the source tree."""
for path, size in DESTINATIONS.items():
build_icons_size(path, size, check, remove)
-def build_icons_size(destination: Path, size: int, check: bool, remove: bool):
+def build_icons_size(destination: Path, size: int, check: bool, remove: bool) -> None:
icon_size = (size, size)
checks_ok = True
apps = coin_info.fido_info()
@@ -55,14 +55,14 @@ def build_icons_size(destination: Path, size: int, check: bool, remove: bool):
continue
im = Image.open(app["icon"])
- resized = im.resize(icon_size, Image.BOX)
+ resized = im.resize(icon_size, Image.BOX) # type: ignore ["BOX" is not a known attribute of module "PIL.Image"]
toi = toif.from_image(resized)
dest_path = destination / f"icon_{app['key']}.toif"
total_size += len(toi.to_bytes())
if not check:
- toi.save(dest_path)
+ toi.save(str(dest_path))
else:
if not dest_path.exists():
print(f"Missing TOIF: {dest_path}")
diff --git a/core/tools/codegen/gen_cert_bundle.py b/core/tools/codegen/gen_cert_bundle.py
index 60bbd893..2237f665 100755
--- a/core/tools/codegen/gen_cert_bundle.py
+++ b/core/tools/codegen/gen_cert_bundle.py
@@ -1,4 +1,5 @@
#!/usr/bin/env python3
+from __future__ import annotations
from base64 import b64decode
from hashlib import sha256
@@ -8,7 +9,7 @@ import requests
REPO = "certifi/python-certifi"
-def fetch_certdata():
+def fetch_certdata() -> tuple[str, str]:
r = requests.get(f"https://api.github.com/repos/{REPO}/git/refs/heads/master")
assert r.status_code == 200
commithash = r.json()["object"]["sha"]
@@ -22,7 +23,7 @@ def fetch_certdata():
return commithash, certdata
-def process_certdata(data):
+def process_certdata(data: str) -> dict[str, bytes]:
certs = {}
lines = [x.strip() for x in data.split("\n")]
label = None
@@ -48,7 +49,7 @@ def process_certdata(data):
return certs
-def main():
+def main() -> None:
commithash, certdata = fetch_certdata()
print(f"# fetched from https://github.com/{REPO}")
diff --git a/core/tools/codegen/gen_font.py b/core/tools/codegen/gen_font.py
index 88415a00..045633f7 100755
--- a/core/tools/codegen/gen_font.py
+++ b/core/tools/codegen/gen_font.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-
+# pyright: reportMissingImports=false
# script used to generate FontInfo in `rust/src/ui/layout_*/fonts/font_*_*.rs`
from __future__ import annotations
@@ -237,6 +237,7 @@ class Glyph:
class FaceProcessor:
+
def __init__(
self,
name: str,
@@ -249,7 +250,7 @@ class FaceProcessor:
gen_upper: bool = False, # generate font with only upper-cased letters
font_idx: int | None = None, # idx to UTF-8 foreign chars data
font_idx_upper: int | None = None, # idx to UTF-8 upper-cased foreign chars
- ):
+ ) -> None:
if gen_normal is False and gen_upper is False:
raise ValueError(
"At least one must be selected from normal glyphs or only uppercased glyphs."
@@ -267,7 +268,7 @@ class FaceProcessor:
self.gen_upper = gen_upper
self.face = freetype.Face(str(FONTS_DIR / f"{name}-{style}.{ext}"))
- self.face.set_pixel_sizes(0, size) # type: ignore
+ self.face.set_pixel_sizes(0, size)
self.fontname = f"{name.lower()}_{style.lower()}_{size}"
self.font_ymin = 0
self.font_ymax = 0
@@ -298,7 +299,7 @@ class FaceProcessor:
self.write_char_widths_files()
self.write_rust_file()
- def write_foreign_json(self, upper_cased=False) -> None:
+ def write_foreign_json(self, upper_cased: bool = False) -> None:
for lang, language_chars in all_languages.items():
fontdata = {}
for item in language_chars:
@@ -358,7 +359,7 @@ class FaceProcessor:
return self.face.get_char_index(ord(c)) != 0
def _load_char(self, c: str) -> None:
- self.face.load_char(c, freetype.FT_LOAD_RENDER | freetype.FT_LOAD_TARGET_NORMAL) # type: ignore
+ self.face.load_char(c, freetype.FT_LOAD_RENDER | freetype.FT_LOAD_TARGET_NORMAL)
# --------------------------------------------------------------------
# Rust code generation
@@ -483,10 +484,10 @@ class FaceProcessor:
# Write the rendered template into the Rust file.
with open(self._rs_file_name, "wt") as f:
- f.write(rendered)
+ f.write(rendered) # type: ignore [Argument of type "bytes | str" cannot be assigned to parameter "s" of type "str" in function "write"]
-def gen_layout_bolt():
+def gen_layout_bolt() -> None:
global LAYOUT_NAME
LAYOUT_NAME = "Bolt"
FaceProcessor("TTHoves", "Regular", 21, ext="otf", font_idx=1).write_files()
@@ -503,7 +504,7 @@ def gen_layout_bolt():
FaceProcessor("RobotoMono", "Medium", 20, font_idx=3).write_files()
-def gen_layout_caesar():
+def gen_layout_caesar() -> None:
global LAYOUT_NAME
LAYOUT_NAME = "Caesar"
FaceProcessor(
@@ -540,7 +541,7 @@ def gen_layout_caesar():
).write_files()
-def gen_layout_delizia():
+def gen_layout_delizia() -> None:
global LAYOUT_NAME
LAYOUT_NAME = "Delizia"
# FIXME: BIG font idx not needed
@@ -559,7 +560,7 @@ def gen_layout_delizia():
).write_files()
-def gen_layout_eckhart():
+def gen_layout_eckhart() -> None:
global LAYOUT_NAME
LAYOUT_NAME = "eckhart"
# FIXME: BIG font idx not needed
@@ -594,7 +595,7 @@ LAYOUTS = {
default=False,
help="Generate character width files",
)
-def main(layout: str | None, write_widths: bool):
+def main(layout: str | None, write_widths: bool) -> None:
"""Generate font files for Trezor firmware."""
global WRITE_WIDTHS
WRITE_WIDTHS = write_widths
diff --git a/core/tools/codegen/gen_keys.py b/core/tools/codegen/gen_keys.py
index 2d0e45c5..465e4a2d 100755
--- a/core/tools/codegen/gen_keys.py
+++ b/core/tools/codegen/gen_keys.py
@@ -5,7 +5,7 @@ import binascii
from trezorlib import _ed25519
-def hex_to_c(s):
+def hex_to_c(s: str) -> str:
return '"\\x' + "\\x".join([s[i : i + 2] for i in range(0, len(s), 2)]) + '"'
diff --git a/core/tools/codegen/gen_loader.py b/core/tools/codegen/gen_loader.py
index 1531b412..a362e7f4 100755
--- a/core/tools/codegen/gen_loader.py
+++ b/core/tools/codegen/gen_loader.py
@@ -5,7 +5,7 @@
import math
-def gen_loader(model, outer, inner):
+def gen_loader(model: str, outer: int, inner: int) -> None:
with open(f"loader_{model}.h", "wt") as f:
f.write("// clang-format off\n")
f.write(f"static const int img_loader_size = {outer};\n" % outer)
diff --git a/core/tools/generate_tropic_model_config.py b/core/tools/generate_tropic_model_config.py
index 0e3ef482..492e297a 100755
--- a/core/tools/generate_tropic_model_config.py
+++ b/core/tools/generate_tropic_model_config.py
@@ -33,7 +33,7 @@ EXTRA_FILES = [
@click.command()
@click.option("--check", is_flag=True)
-def generate_config(check):
+def generate_config(check: bool) -> None:
tropic_key = serialization.load_pem_private_key(
TROPIC_KEY.read_bytes(), password=None
)
@@ -67,7 +67,7 @@ def generate_config(check):
# certificate chain with the length prefix
all_cert_bytes = (
- (len(tropic_cert_der_bytes) + len(root_cert_der_bytes)).to_bytes(2)
+ (len(tropic_cert_der_bytes) + len(root_cert_der_bytes)).to_bytes(2, "big")
+ tropic_cert_der_bytes
+ root_cert_der_bytes
)
diff --git a/core/tools/hid-bridge/hid_interface.py b/core/tools/hid-bridge/hid_interface.py
index cbe55dca..f0a11976 100644
--- a/core/tools/hid-bridge/hid_interface.py
+++ b/core/tools/hid-bridge/hid_interface.py
@@ -1,31 +1,34 @@
+# pyright: reportMissingImports=false
+from __future__ import annotations
+
import os
import logger
import uhid
-def random_bytes(length):
+def random_bytes(length: int) -> bytes:
return os.urandom(length)
class HIDInterface:
uhid_device = "/dev/uhid"
- def __init__(self):
+ def __init__(self) -> None:
self.file_descriptor = os.open(HIDInterface.uhid_device, os.O_RDWR)
self.create_device()
- def __uhid_read(self, length):
+ def __uhid_read(self, length: int) -> bytes:
data = os.read(self.file_descriptor, length)
logger.log_raw(f"{HIDInterface.uhid_device} >", data.hex())
return data
- def __uhid_write(self, data):
+ def __uhid_write(self, data: bytes) -> None:
bytes_written = os.write(self.file_descriptor, data)
assert bytes_written == len(data)
logger.log_raw(f"{HIDInterface.uhid_device} <", data.hex())
- def create_device(self):
+ def create_device(self) -> None:
name = b"Virtual Trezor"
phys = b""
uniq = random_bytes(64)
@@ -73,13 +76,13 @@ class HIDInterface:
f"rd_data=0x{rd_data.hex()}",
)
- def write_data(self, data):
+ def write_data(self, data: bytes) -> None:
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_hid_packet("DEVICE_OUTPUT", f"0x{data.hex()}")
- def process_event(self):
+ def process_event(self) -> bytes | None:
ev_type, request = uhid.parse_event(self.__uhid_read(uhid.EVENT_LENGTH))
if ev_type == uhid.EVENT_TYPE_START:
(dev_flags,) = request
diff --git a/core/tools/hid-bridge/logger.py b/core/tools/hid-bridge/logger.py
index b8a71ae3..84cdf713 100644
--- a/core/tools/hid-bridge/logger.py
+++ b/core/tools/hid-bridge/logger.py
@@ -1,21 +1,23 @@
+from __future__ import annotations
+
import datetime
log_level = "None"
log_timestamps = False
-def __get_timestamp():
+def __get_timestamp() -> str:
return str(datetime.datetime.now())
-def __log_message(message):
+def __log_message(message: str) -> None:
if log_timestamps:
print(f"{__get_timestamp()}\t{message}")
else:
print(message)
-def log_uhid_event(event_name, params=None):
+def log_uhid_event(event_name: str, params: str | None = None) -> None:
if log_level == "uhid-event":
if params:
__log_message(f"{event_name}\t{params}")
@@ -23,11 +25,11 @@ def log_uhid_event(event_name, params=None):
__log_message(event_name)
-def log_hid_packet(packet_name, payload):
+def log_hid_packet(packet_name: str, payload: str) -> None:
if log_level == "hid-packet":
__log_message(f"{packet_name}\t{payload}")
-def log_raw(direction, payload):
+def log_raw(direction: str, payload: str) -> None:
if log_level == "raw":
__log_message(f"{direction}\t{payload}")
diff --git a/core/tools/hid-bridge/udp_interface.py b/core/tools/hid-bridge/udp_interface.py
index dbc360d8..07162222 100644
--- a/core/tools/hid-bridge/udp_interface.py
+++ b/core/tools/hid-bridge/udp_interface.py
@@ -1,10 +1,12 @@
+# pyright: reportMissingImports=false
import socket
import logger
class UDPInterface:
- def __init__(self, destination_port):
+
+ def __init__(self, destination_port: int) -> None:
self.bind_ip = "127.0.0.1"
self.bind_port = 21423
@@ -16,7 +18,7 @@ class UDPInterface:
self.file_descriptor = self.socket.fileno()
- def write(self, data):
+ def write(self, data: bytes) -> None:
bytes_sent = self.socket.sendto(
data, ((self.destination_ip, self.destination_port))
)
@@ -26,7 +28,7 @@ class UDPInterface:
data.hex(),
)
- def read(self, length):
+ def read(self, length: int) -> bytes:
data, address = self.socket.recvfrom(length)
logger.log_raw(
f"{self.bind_ip}:{self.bind_port} < {address[0]}:{address[1]}",
diff --git a/core/tools/hid-bridge/uhid.py b/core/tools/hid-bridge/uhid.py
index 4e121374..89abb5ce 100644
--- a/core/tools/hid-bridge/uhid.py
+++ b/core/tools/hid-bridge/uhid.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import struct
EVENT_TYPE_START = 2
@@ -17,15 +19,15 @@ START_REQ_FMT = "< Q"
OUTPUT_REQ_FMT = f"< {DATA_MAX}s H B"
-def pack_event(ev_type, request):
+def pack_event(ev_type: int, request: bytes) -> bytes:
return ev_type.to_bytes(4, byteorder="little") + request
-def unpack_event(buf):
+def unpack_event(buf: bytes) -> tuple[int, bytes]:
return int.from_bytes(buf[:4], byteorder="little"), buf[4:]
-def parse_event(event):
+def parse_event(event: bytes) -> tuple[int, bytes | list | tuple[bytes]]:
assert len(event) == EVENT_LENGTH
ev_type, request = unpack_event(event)
@@ -47,8 +49,16 @@ def parse_event(event):
def create_create2_event(
- name, phys, uniq, bus, vendor, product, version, country, rd_data
-):
+ name: bytes,
+ phys: bytes,
+ uniq: bytes,
+ bus: int,
+ vendor: int,
+ product: int,
+ version: int,
+ country: int,
+ rd_data: bytes,
+) -> bytes:
uhid_create2_req = struct.pack(
CREATE2_REQ_FMT,
name,
@@ -67,7 +77,7 @@ def create_create2_event(
return event
-def create_input2_event(data):
+def create_input2_event(data: bytes) -> bytes:
uhid_input2_req = struct.pack(INPUT2_REQ_FMT, len(data), data)
event = pack_event(EVENT_TYPE_INTPUT2, uhid_input2_req)
return event
diff --git a/core/tools/jpg_to_h.py b/core/tools/jpg_to_h.py
index f353f3d1..af2d79cf 100644
--- a/core/tools/jpg_to_h.py
+++ b/core/tools/jpg_to_h.py
@@ -3,6 +3,7 @@ Creates a header file containing image data.
"""
import pathlib
+from typing import BinaryIO
import click
@@ -15,7 +16,7 @@ unsigned int {name}_jpg_len = {length};
@click.command()
@click.argument("infile", type=click.File("rb"))
-def convert(infile):
+def convert(infile: BinaryIO) -> None:
path = pathlib.Path(infile.name)
diff --git a/core/tools/make_cmakelists.py b/core/tools/make_cmakelists.py
index ba0ef276..1d80d67e 100644
--- a/core/tools/make_cmakelists.py
+++ b/core/tools/make_cmakelists.py
@@ -1,7 +1,8 @@
import argparse
+from typing import Iterable
-def gen(sources, dirs, defs):
+def gen(sources: Iterable[str], dirs: Iterable[str], defs: Iterable[str]) -> None:
target = "CMakeLists.txt"
with open(target, "w") as f:
diff --git a/core/tools/provision_device.py b/core/tools/provision_device.py
index 4b37d766..b92e6daf 100644
--- a/core/tools/provision_device.py
+++ b/core/tools/provision_device.py
@@ -156,7 +156,7 @@ def cli() -> None:
@cli.command()
@click.option("-d", "--device", default="/dev/ttyACM0", help="Device path")
-def identify(device) -> None:
+def identify(device: str) -> None:
connection = Connection(device)
connection.command("ping")
DeviceInfo.read(connection)
@@ -165,7 +165,7 @@ def identify(device) -> None:
@cli.command()
@click.option("-d", "--device", default="/dev/ttyACM0", help="Device path")
@click.option("--wipe", is_flag=True, help="Wipe the device")
-def lock(device, wipe) -> None:
+def lock(device: str, wipe: bool) -> None:
connection = Connection(device)
connection.command("ping")
connection.command("optiga-lock")
@@ -183,7 +183,7 @@ def lock(device, wipe) -> None:
@click.option(
"--lock/--no-lock", default=True, help="Lock the device after provisioning"
)
-def provision(url, device, model, no_verify, lock) -> None:
+def provision(url: str, device: str, model: str, no_verify: bool, lock: bool) -> None:
global SERVER_TOKEN
SERVER_TOKEN = os.environ.get("SERVER_TOKEN")
@@ -195,9 +195,9 @@ def provision(url, device, model, no_verify, lock) -> None:
connection.command("ping")
# grab CPUID, OPTIGAID and device certificate
- device = DeviceInfo.read(connection)
+ device_info = DeviceInfo.read(connection)
# call the provisioning server
- result = provision_request(device, url, model, not no_verify)
+ result = provision_request(device_info, url, model, not no_verify)
# write provisioning result to the device
result.write(connection)
diff --git a/core/tools/size/apps.py b/core/tools/size/apps.py
index 085dad52..be405e04 100755
--- a/core/tools/size/apps.py
+++ b/core/tools/size/apps.py
@@ -17,7 +17,7 @@ CORE_DIR = HERE.parent.parent
if len(sys.argv) > 1:
BIN_TO_ANALYZE = sys.argv[1]
else:
- BIN_TO_ANALYZE = CORE_DIR / "build/firmware/firmware.elf" # type: ignore
+ BIN_TO_ANALYZE = CORE_DIR / "build/firmware/firmware.elf"
def apps_categories(row: DataRow) -> str | None:
diff --git a/core/tools/size/checker.py b/core/tools/size/checker.py
index 09a66136..66d823e3 100755
--- a/core/tools/size/checker.py
+++ b/core/tools/size/checker.py
@@ -18,7 +18,7 @@ CORE_DIR = HERE.parent.parent
if len(sys.argv) > 1:
BIN_TO_ANALYZE = sys.argv[1]
else:
- BIN_TO_ANALYZE = CORE_DIR / "build/firmware/firmware.elf" # type: ignore
+ BIN_TO_ANALYZE = CORE_DIR / "build/firmware/firmware.elf"
# Comes from `core/embed/projects/firmware/memory_T.ld`
FLASH_SIZE_KB = 768
@@ -40,7 +40,7 @@ def report_section(name: str, size: int, max_size: int) -> None:
print(
f"Less free space in {name} ({free}K) than expected ({MIN_KB_FREE_TO_SUCCEED}K). Failing"
)
- EXIT_CODE = 1 # type: ignore
+ EXIT_CODE = 1
if __name__ == "__main__":
diff --git a/core/tools/size/groups.py b/core/tools/size/groups.py
index abfd8faa..bdb2f2ef 100755
--- a/core/tools/size/groups.py
+++ b/core/tools/size/groups.py
@@ -17,7 +17,7 @@ CORE_DIR = HERE.parent.parent
if len(sys.argv) > 1:
BIN_TO_ANALYZE = sys.argv[1]
else:
- BIN_TO_ANALYZE = CORE_DIR / "build/firmware/firmware.elf" # type: ignore
+ BIN_TO_ANALYZE = CORE_DIR / "build/firmware/firmware.elf"
FILE_TO_SAVE = HERE / "size_binary_firmware_elf_results.txt"
diff --git a/core/tools/snippets/change_icon_format.py b/core/tools/snippets/change_icon_format.py
index 5d020783..68b19d00 100644
--- a/core/tools/snippets/change_icon_format.py
+++ b/core/tools/snippets/change_icon_format.py
@@ -156,7 +156,7 @@ def reformat_toif_icons(p: str | Path) -> None:
reformat_toif_icon(os.path.join(p, file))
-def change_icon_format():
+def change_icon_format() -> None:
# bootloader icons
reformat_c_icons(CORE_DIR / "embed/projects/bootloader")
diff --git a/core/tools/translations/check_missing_upy.py b/core/tools/translations/check_missing_upy.py
index 57d2c1d4..219e5033 100644
--- a/core/tools/translations/check_missing_upy.py
+++ b/core/tools/translations/check_missing_upy.py
@@ -1,9 +1,10 @@
+# pyright: reportAttributeAccessIssue=false, reportArgumentType=false
+
from __future__ import annotations
import ast
import json
from pathlib import Path
-from typing import Any
HERE = Path(__file__).parent
CORE = HERE.parent.parent
@@ -17,7 +18,7 @@ if IGNORE_FILE.exists():
content = json.loads(IGNORE_FILE.read_text())
IGNORE_SET: set[str] = set(content.keys())
else:
- IGNORE_SET = set() # type: ignore
+ IGNORE_SET = set()
def find_all_strings(filename: str | Path) -> list[str]:
@@ -28,13 +29,15 @@ def find_all_strings(filename: str | Path) -> list[str]:
strings: list[str] = []
class StringVisitor(ast.NodeVisitor):
- def visit_Str(self, node: ast.Str):
- strings.append(node.s)
- def visit_JoinedStr(self, node: ast.JoinedStr):
+ def visit_Constant(self, node: ast.Constant) -> None:
+ if isinstance(node.value, str):
+ strings.append(node.value)
+
+ def visit_JoinedStr(self, node: ast.JoinedStr) -> None:
for value in node.values:
- if isinstance(value, ast.Str):
- strings.append(value.s)
+ if isinstance(value, ast.Constant) and isinstance(value.value, str):
+ strings.append(value.value)
visitor = StringVisitor()
visitor.visit(tree)
@@ -88,19 +91,20 @@ def find_strings_to_ignore(filename: str | Path) -> list[str]:
return ""
def include_all_strings(arg: ast.expr) -> None:
- if isinstance(arg, ast.Str):
- strings.append(arg.s)
+ if isinstance(arg, ast.Constant) and isinstance(arg.value, str):
+ strings.append(arg.value)
elif isinstance(arg, ast.JoinedStr):
for value in arg.values:
- if isinstance(value, ast.Str):
- strings.append(value.s)
+ if isinstance(value, ast.Constant) and isinstance(value.value, str):
+ strings.append(value.value)
elif isinstance(value, ast.FormattedValue):
# This part is an expression inside an f-string
expr_as_str = ast.dump(value.value, annotate_fields=False)
strings.append(expr_as_str)
class IgnoreStringVisitor(ast.NodeVisitor):
- def visit_Call(self, node: ast.Call):
+
+ def visit_Call(self, node: ast.Call) -> None:
func_name = get_final_attribute_name(node.func)
if ignore_func(func_name):
for arg in node.args + [kw.value for kw in node.keywords]:
@@ -108,13 +112,13 @@ def find_strings_to_ignore(filename: str | Path) -> list[str]:
# Continue visiting the children of this node (!!!Necessary!!!)
self.generic_visit(node)
- def visit_Assert(self, node: ast.Assert):
+ def visit_Assert(self, node: ast.Assert) -> None:
error_message = node.msg
if error_message:
include_all_strings(error_message)
self.generic_visit(node)
- def visit_Assign(self, node: ast.Assign):
+ def visit_Assign(self, node: ast.Assign) -> None:
ignore_variables = [
"msg_wire",
"msg_type",
@@ -125,7 +129,7 @@ def find_strings_to_ignore(filename: str | Path) -> list[str]:
include_all_strings(value)
self.generic_visit(node)
- def visit_FunctionDef(self, node: ast.FunctionDef):
+ def visit_FunctionDef(self, node: ast.FunctionDef) -> None:
for arg in node.args.args:
annotation = arg.annotation
if annotation:
@@ -135,7 +139,7 @@ def find_strings_to_ignore(filename: str | Path) -> list[str]:
include_all_strings(return_annotation)
self.generic_visit(node)
- def visit_AsyncFunctionDef(self, node: ast.AsyncFunctionDef) -> Any:
+ def visit_AsyncFunctionDef(self, node: ast.AsyncFunctionDef) -> None:
for arg in node.args.args:
annotation = arg.annotation
if annotation:
@@ -145,7 +149,7 @@ def find_strings_to_ignore(filename: str | Path) -> list[str]:
include_all_strings(return_annotation)
self.generic_visit(node)
- def visit_AnnAssign(self, node: ast.AnnAssign):
+ def visit_AnnAssign(self, node: ast.AnnAssign) -> None:
annotation = node.annotation
include_all_strings(annotation)
self.generic_visit(node)
@@ -158,7 +162,7 @@ def find_strings_to_ignore(filename: str | Path) -> list[str]:
if isinstance(node, ast.Expr) and isinstance(
node.value, (ast.Str, ast.JoinedStr)
):
- strings.append(node.value.s) # type: ignore
+ strings.append(node.value.s)
return strings
@@ -268,5 +272,5 @@ if __name__ == "__main__":
check_folder_resursive_report(folder, ignore_files=ignore_files)
# file = CORE_SRC / "trezor/ui/layouts/tt_v2/reset.py"
- # KEY_PREFIX = "TR.reset" # type: ignore
+ # KEY_PREFIX = "TR.reset"
# check_file_report(file)
diff --git a/core/tools/translations/flatten_json.py b/core/tools/translations/flatten_json.py
index c306b6f9..1f32b407 100644
--- a/core/tools/translations/flatten_json.py
+++ b/core/tools/translations/flatten_json.py
@@ -1,3 +1,4 @@
+# pyright: reportMissingImports=false
from __future__ import annotations
import json
diff --git a/core/tools/translations/sort_keys.py b/core/tools/translations/sort_keys.py
index 581aa8aa..051989e2 100755
--- a/core/tools/translations/sort_keys.py
+++ b/core/tools/translations/sort_keys.py
@@ -1,4 +1,5 @@
#!/usr/bin/env python3
+# pyright: reportMissingImports=false
import json
import sys
from enum import Enum, auto
@@ -41,7 +42,7 @@ def process_file(lang_file: Path, check_only: bool) -> FileStatus:
return FileStatus.OK
-def main():
+def main() -> None:
mode = sys.argv[1] if len(sys.argv) > 1 else "format"
check_only = mode == "check"
diff --git a/core/tools/translations/translate_missing.py b/core/tools/translations/translate_missing.py
index 61ec0eab..b100779f 100644
--- a/core/tools/translations/translate_missing.py
+++ b/core/tools/translations/translate_missing.py
@@ -1,3 +1,4 @@
+# pyright: reportMissingImports=false
import json
from typing import Any, Dict
diff --git a/core/tools/translations/validate_same_keys.py b/core/tools/translations/validate_same_keys.py
index 3445a352..f27c53be 100644
--- a/core/tools/translations/validate_same_keys.py
+++ b/core/tools/translations/validate_same_keys.py
@@ -1,3 +1,4 @@
+# pyright: reportMissingImports=false
from __future__ import annotations
import json
diff --git a/core/tools/translations/validate_strings.py b/core/tools/translations/validate_strings.py
index caaede30..ef677619 100644
--- a/core/tools/translations/validate_strings.py
+++ b/core/tools/translations/validate_strings.py
@@ -1,3 +1,4 @@
+# pyright: reportMissingImports=false
from __future__ import annotations
import json
diff --git a/core/tools/trezor_core_tools/bootloader_hashes.py b/core/tools/trezor_core_tools/bootloader_hashes.py
index cb874cf1..70bb23bf 100755
--- a/core/tools/trezor_core_tools/bootloader_hashes.py
+++ b/core/tools/trezor_core_tools/bootloader_hashes.py
@@ -6,7 +6,8 @@ from pathlib import Path
import click
import construct as c
-from trezorlib.firmware.core import BootableImage, FirmwareImage, Model
+from trezorlib.firmware.core import BootableImage, FirmwareImage
+from trezorlib.firmware.models import Model
from .common import MODELS_DIR
from .layout_parser import find_value
@@ -97,7 +98,7 @@ def bootloader_str(file: Path, model: str) -> str:
@click.command()
@click.option("-c", "--check", is_flag=True, help="Do not write, only check.")
-def main(check):
+def main(check: bool) -> None:
models = list(MODELS_DIR.iterdir())
diff --git a/core/tools/trezor_core_tools/hash_signer.py b/core/tools/trezor_core_tools/hash_signer.py
index f7a124ab..62bd0bd3 100755
--- a/core/tools/trezor_core_tools/hash_signer.py
+++ b/core/tools/trezor_core_tools/hash_signer.py
@@ -1,4 +1,6 @@
#!/usr/bin/env python3
+from __future__ import annotations
+
from typing import Sequence
import click
@@ -18,6 +20,7 @@ def _make_dev_keys(*key_bytes: bytes) -> Sequence[bytes]:
"--digest",
"digest",
help="Digest to be signed.",
+ required=True,
)
@click.option(
"-s0",
@@ -40,7 +43,7 @@ def _make_dev_keys(*key_bytes: bytes) -> Sequence[bytes]:
is_flag=True,
help="Print out sigmask",
)
-def main(digest, getsig0, getsig1, getmask):
+def main(digest: str, getsig0: bool, getsig1: bool, getmask: bool) -> None:
DEV_KEYS = _make_dev_keys(b"\x44", b"\x45")
diff --git a/core/tools/trezor_core_tools/headertool.py b/core/tools/trezor_core_tools/headertool.py
index 049acad7..041609e0 100755
--- a/core/tools/trezor_core_tools/headertool.py
+++ b/core/tools/trezor_core_tools/headertool.py
@@ -1,5 +1,7 @@
#!/usr/bin/env python3
-from typing import List, Tuple
+from __future__ import annotations
+
+from typing import Any, BinaryIO, List, Tuple
import click
@@ -29,6 +31,7 @@ def do_rehash(fw: firmware_headers.SignableImageProto) -> None:
if isinstance(fw, firmware.FirmwareImage):
fw.header.hashes = fw.code_hashes()
if isinstance(fw, firmware.SecmonImage):
+ assert isinstance(fw.header, firmware.SecmonHeader)
fw.header.hash = fw.code_hash()
elif isinstance(fw, firmware_headers.VendorFirmware):
fw.firmware.header.hashes = fw.firmware.code_hashes()
@@ -38,7 +41,9 @@ def do_rehash(fw: firmware_headers.SignableImageProto) -> None:
# ===================== CLI actions =========================
-def do_replace_vendorheader(fw, vh_file) -> None:
+def do_replace_vendorheader(
+ fw: firmware_headers.SignableImageProto, vh_file: BinaryIO
+) -> None:
if not isinstance(fw, firmware_headers.VendorFirmware):
raise click.ClickException("Invalid image type (must be firmware).")
@@ -49,7 +54,7 @@ def do_replace_vendorheader(fw, vh_file) -> None:
fw.vendor_header = vh
-def no_echo(*args, **kwargs):
+def no_echo(*args: Any, **kwargs: Any) -> None:
"""A no-op function to replace click.echo when quiet mode is enabled."""
pass
@@ -88,17 +93,17 @@ def no_echo(*args, **kwargs):
@click.option("-q", "--quiet", is_flag=True, help="Do not print anything.")
@click.argument("firmware_file", type=click.File("rb+"))
def cli(
- firmware_file,
- verbose,
- rehash,
- dry_run,
- privkey_data,
- sign_dev_keys,
- insert_signature,
- replace_vendor_header,
- print_digest,
- quiet,
-):
+ firmware_file: BinaryIO,
+ verbose: bool,
+ rehash: bool,
+ dry_run: bool,
+ privkey_data: list[str],
+ sign_dev_keys: bool,
+ insert_signature: tuple[str, str] | None,
+ replace_vendor_header: BinaryIO | None,
+ print_digest: bool,
+ quiet: bool,
+) -> None:
"""Manage firmware headers.
This tool supports three types of files: raw vendor headers (TRZV), bootloader
diff --git a/core/tools/trezor_core_tools/headertool_pq.py b/core/tools/trezor_core_tools/headertool_pq.py
index 85a9f01a..1013c370 100755
--- a/core/tools/trezor_core_tools/headertool_pq.py
+++ b/core/tools/trezor_core_tools/headertool_pq.py
@@ -1,10 +1,14 @@
#!/usr/bin/env python3
+from __future__ import annotations
+
+from typing import Any, BinaryIO
+
import click
from trezorlib._internal import firmware_headers
-def no_echo(*args, **kwargs):
+def no_echo(*args: Any, **kwargs: Any) -> None:
"""A no-op function to replace click.echo when quiet mode is enabled."""
pass
@@ -32,14 +36,14 @@ def no_echo(*args, **kwargs):
@click.option("-q", "--quiet", is_flag=True, help="Do not print anything.")
@click.argument("firmware_file", type=click.File("rb+"))
def cli(
- firmware_file,
- verbose,
- dry_run,
- sign_dev_keys,
- merkle_proof,
- print_merkle_root,
- quiet,
-):
+ firmware_file: BinaryIO,
+ verbose: bool,
+ dry_run: bool,
+ sign_dev_keys: bool,
+ merkle_proof: list[str],
+ print_merkle_root: bool,
+ quiet: bool,
+) -> None:
"""Manage firmware headers.
This tool supports new bootloader header (TRZQ) with PQC signature. Other
diff --git a/python/src/trezorlib/_internal/firmware_headers.py b/python/src/trezorlib/_internal/firmware_headers.py
index c8b60458..a804a89a 100644
--- a/python/src/trezorlib/_internal/firmware_headers.py
+++ b/python/src/trezorlib/_internal/firmware_headers.py
@@ -187,7 +187,7 @@ def format_header(
def format_secmon_header(
- header: firmware.secmon.SecmonHeader,
+ header: firmware.SecmonHeader,
code_hash: bytes,
digest: bytes,
sig_status: Status,
diff --git a/tools/automatic_battery_tester/analysis/temperature_analysis.py b/tools/automatic_battery_tester/analysis/temperature_analysis.py
index a1e27d7e..64817992 100644
--- a/tools/automatic_battery_tester/analysis/temperature_analysis.py
+++ b/tools/automatic_battery_tester/analysis/temperature_analysis.py
@@ -1,5 +1,8 @@
+from __future__ import annotations
+
import sys
from pathlib import Path
+from typing import Any
import matplotlib.pyplot as plt
from InquirerPy import inquirer
@@ -12,7 +15,9 @@ battery_thermal_limit = 45.0 # Celsius
case_thermal_limit = 41.0 # Celsius
-def select_waveforms(dataset_directory=default_dataset_dir):
+def select_waveforms(
+ dataset_directory: Path = default_dataset_dir,
+) -> list[dict[str, Path]]:
"""
Select waveforms from a given dataset directory.
@@ -74,7 +79,14 @@ def select_waveforms(dataset_directory=default_dataset_dir):
return selected
-def colored_region_plot(axis, time_vector, data_vector, mask, color="red", alpha=0.5):
+def colored_region_plot(
+ axis: plt.Axes,
+ time_vector: Any,
+ data_vector: Any,
+ mask: Any,
+ color: str = "red",
+ alpha: float = 0.5,
+) -> None:
start = None
in_region = False
@@ -100,7 +112,13 @@ def colored_region_plot(axis, time_vector, data_vector, mask, color="red", alpha
)
-def colored_region_box(axis, time_vector, mask, color="orange", alpha=0.5):
+def colored_region_box(
+ axis: plt.Axes,
+ time_vector: Any,
+ mask: Any,
+ color: str = "orange",
+ alpha: float = 0.5,
+) -> None:
start = None
in_region = False
@@ -118,11 +136,11 @@ def colored_region_box(axis, time_vector, mask, color="orange", alpha=0.5):
axis.axvspan(time_vector[start], time_vector[-1], color=color, alpha=alpha)
-def sec_to_min(time_vector):
+def sec_to_min(time_vector: Any) -> Any:
return (time_vector - time_vector[0]) / 60.0
-def plot_temperature_profile(waveform_name, profile_data):
+def plot_temperature_profile(waveform_name: str, profile_data: Any) -> None:
fig, ax = plt.subplots(2)
fig.canvas.manager.set_window_title(waveform_name)
@@ -180,10 +198,10 @@ def plot_temperature_profile(waveform_name, profile_data):
ax[0].legend()
ax[0].grid(True)
- def min_to_hr(x):
+ def min_to_hr(x: float) -> float:
return x / 60.0
- def hr_to_min(x):
+ def hr_to_min(x: float) -> float:
return x * 60.0
secax = ax[0].secondary_xaxis("top", functions=(min_to_hr, hr_to_min))
@@ -235,12 +253,12 @@ def plot_temperature_profile(waveform_name, profile_data):
)
-def main():
+def main() -> None:
selected_waveforms = select_waveforms()
for waveform in selected_waveforms:
-
+ assert waveform["waveform"] is not None
# Load data from files
profile_data = load_measured_data(
data_file_path=waveform["waveform"],
diff --git a/tools/automatic_battery_tester/analysis/utils/data_convertor.py b/tools/automatic_battery_tester/analysis/utils/data_convertor.py
index baed97c1..51233e69 100644
--- a/tools/automatic_battery_tester/analysis/utils/data_convertor.py
+++ b/tools/automatic_battery_tester/analysis/utils/data_convertor.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from dataclasses import dataclass
from pathlib import Path
@@ -26,7 +28,7 @@ class BatteryAnalysisData:
def load_measured_data(
- data_file_path: Path, extern_temp_file_path: Path = None
+ data_file_path: Path, extern_temp_file_path: Path | None = None
) -> BatteryAnalysisData:
profile_data = pd.read_csv(data_file_path)
diff --git a/tools/automatic_battery_tester/dut/dut.py b/tools/automatic_battery_tester/dut/dut.py
index 25848269..d61f0b6e 100644
--- a/tools/automatic_battery_tester/dut/dut.py
+++ b/tools/automatic_battery_tester/dut/dut.py
@@ -1,8 +1,11 @@
+from __future__ import annotations
+
import hashlib
import logging
import time
from dataclasses import dataclass, field
from pathlib import Path
+from typing import Any
import serial
from hardware_ctl.relay_controller import RelayController
@@ -44,13 +47,13 @@ class Dut:
def __init__(
self,
- name,
- cpu_id=None,
- usb_port=None,
- relay_port=None,
+ name: str,
+ cpu_id: str | None = None,
+ usb_port: str | None = None,
+ relay_port: int | None = None,
relay_ctl: RelayController | None = None,
- verbose=False,
- ):
+ verbose: bool = False,
+ ) -> None:
self.name = name
self.relay_ctl = relay_ctl
@@ -106,7 +109,7 @@ class Dut:
# device should start charging
report = self.read_report()
- if not report.usb == "USB_connected":
+ if not report or not report.usb == "USB_connected":
self.init_error()
raise RuntimeError(
f"{self.name} USB not connected. Check VCP and relay ports"
@@ -116,26 +119,26 @@ class Dut:
self.disable_charging()
self.power_down()
- def init_error(self):
+ def init_error(self) -> None:
self.display_error()
self.disable_charging()
self.power_down()
- def display_error(self):
+ def display_error(self) -> None:
self.display_bars("R")
time.sleep(3)
- def display_ok(self):
+ def display_ok(self) -> None:
self.display_bars("G")
time.sleep(3)
- def get_cpu_id_hash(self):
+ def get_cpu_id_hash(self) -> str:
return self.cpu_id_hash
- def get_relay_port(self):
+ def get_relay_port(self) -> int | None:
return self.relay_port
- def generate_id_hash(self, cpu_id):
+ def generate_id_hash(self, cpu_id: str | None) -> str:
"""
Generate a unique ID hash for the DUT based on its CPU ID.
:param cpu_id: The CPU ID of the DUT.
@@ -148,35 +151,37 @@ class Dut:
digest = hashlib.sha256(device_id_bytes).digest()
return digest[:2].hex()
- def set_verbose(self, verbose):
+ def set_verbose(self, verbose: bool) -> None:
self.verbose = verbose
- def get_verbose(self):
+ def get_verbose(self) -> bool:
return self.verbose
- def entry_interactive_mode(self):
+ def entry_interactive_mode(self) -> None:
# Enter interactive mode
self.send_command(".", skip_response=True)
- def power_up(self):
+ def power_up(self) -> None:
"""
Power up the DUT by activating the relay.
"""
if self.relay_port is None:
logging.debug("Relay port not set for DUT, skipping power up.")
return
+ assert self.relay_ctl is not None
self.relay_ctl.set_relay_on(self.relay_port)
- def power_down(self):
+ def power_down(self) -> None:
"""
Power down the DUT by deactivating the relay.
"""
if self.relay_port is None:
logging.debug("Relay port not set for DUT, skipping power down.")
return
+ assert self.relay_ctl is not None
self.relay_ctl.set_relay_off(self.relay_port)
- def display_bars(self, value: str):
+ def display_bars(self, value: str) -> bool:
"""
Display bars on the DUT's screen.
:param value: A string representing the bars to display (e.g., "G" for green).
@@ -185,7 +190,7 @@ class Dut:
response = self.send_command("display-bars", value)
return response.OK
- def ping(self):
+ def ping(self) -> bool:
"""
Send a ping command to the DUT and wait for a response.
Returns True if the DUT responds with "OK", False otherwise.
@@ -193,17 +198,17 @@ class Dut:
response = self.send_command("ping")
return response.OK
- def enable_charging(self):
+ def enable_charging(self) -> bool:
response = self.send_command("pm-charge-enable")
return response.OK
- def disable_charging(self):
+ def disable_charging(self) -> bool:
response = self.send_command("pm-charge-disable")
return response.OK
- def set_soc_limit(self, soc_limit: int):
+ def set_soc_limit(self, soc_limit: int) -> bool:
"""
Set the state of charge (SoC) limit for the DUT.
:param soc_limit: The SoC limit to set (0-100).
@@ -215,7 +220,7 @@ class Dut:
response = self.send_command("pm-set-soc-limit", soc_limit)
return response.OK
- def set_backlight(self, value: int):
+ def set_backlight(self, value: int) -> bool:
if not 0 <= value <= 255:
raise ValueError("Backlight value must be between 0 and 255.")
@@ -224,7 +229,7 @@ class Dut:
return response.OK
- def get_cpuid(self):
+ def get_cpuid(self) -> str | None:
response = self.send_command("get-cpuid")
if not response.OK:
@@ -239,6 +244,7 @@ class Dut:
def parse_report(self, response: DutProdtestResponse) -> DutReportData:
data = DutReportData()
+ assert response.timestamp is not None
data.time = response.timestamp
data.power_state = response.data_entries[0][0]
data.usb = response.data_entries[0][1]
@@ -256,7 +262,7 @@ class Dut:
return data
- def read_report(self) -> DutReportData:
+ def read_report(self) -> DutReportData | None:
"""
Read the PM report from the DUT.
Returns a ProdtestResponse object containing the report data.
@@ -268,10 +274,12 @@ class Dut:
return self.parse_report(response)
- def send_command(self, cmd, *args, skip_response=False):
+ def send_command(
+ self, cmd: str, *args: Any, skip_response: bool = False
+ ) -> DutProdtestResponse:
if self.vcp is None:
- raise "VPC not initalized"
+ raise RuntimeError("VPC not initalized")
response = DutProdtestResponse()
# assert(len == 0)
@@ -326,12 +334,12 @@ class Dut:
def log_data(
self,
output_directory: Path,
- test_time_id,
- test_scenario,
- test_phase,
- temp,
- verbose=False,
- ):
+ test_time_id: str,
+ test_scenario: str,
+ test_phase: str,
+ temp: str,
+ verbose: bool = False,
+ ) -> None:
# Log file name format:
# > <device_id_hash>.<time_identifier>.<test_scenario>.<test><temperarture>.csv
@@ -366,17 +374,17 @@ class Dut:
if verbose:
print(str(report.timestamp) + "," + ",".join(report.data_entries[0]))
- def _log_output(self, message):
+ def _log_output(self, message: str) -> None:
if self.verbose:
prefix = f"\033[95m[{self.name}]\033[0m"
logging.debug(prefix + " > " + message)
- def _log_input(self, message):
+ def _log_input(self, message: str) -> None:
if self.verbose:
prefix = f"\033[95m[{self.name}]\033[0m"
logging.debug(prefix + " < " + message)
- def close(self):
+ def close(self) -> None:
"""
Close the DUT's serial port and clean up resources.
"""
@@ -390,7 +398,7 @@ class Dut:
self.relay_ctl = None
self.relay_port = None
- def __del__(self):
+ def __del__(self) -> None:
try:
if hasattr(self, "vcp") and self.vcp is not None and self.vcp.is_open:
self.close()
diff --git a/tools/automatic_battery_tester/dut/dut_controller.py b/tools/automatic_battery_tester/dut/dut_controller.py
index 0cc4b6c0..a6a4eae1 100644
--- a/tools/automatic_battery_tester/dut/dut_controller.py
+++ b/tools/automatic_battery_tester/dut/dut_controller.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import logging
import sys
from dataclasses import dataclass
@@ -27,7 +29,7 @@ class ProdtestPmReport:
system_voltage: float = 0.0
@classmethod
- def from_string_list(cls, data):
+ def from_string_list(cls, data: list[str]) -> "ProdtestPmReport":
"""Parse a list of strings into a ProdtestPmReport instance."""
try:
return cls(
@@ -56,7 +58,9 @@ class DutController:
provides direct simultaneous control of configured DUTs
"""
- def __init__(self, duts, relay_ctl: RelayController, verbose: bool = False):
+ def __init__(
+ self, duts: list[dict], relay_ctl: RelayController, verbose: bool = False
+ ) -> None:
self.duts = []
self.relay_ctl = relay_ctl
@@ -91,17 +95,17 @@ class DutController:
logging.error("No DUTs initialized. Cannot proceed.")
raise RuntimeError("No DUTs initialized. Check port configuration.")
- def power_up_all(self):
+ def power_up_all(self) -> None:
for d in self.duts:
d.power_up()
- def power_down_all(self):
+ def power_down_all(self) -> None:
for d in self.duts:
d.power_down()
- def enable_charging(self):
+ def enable_charging(self) -> None:
"""
Enable charging on all DUTs.
"""
@@ -111,7 +115,7 @@ class DutController:
except Exception as e:
logging.error(f"Failed to enable charging on {d.name}: {e}")
- def disable_charging(self):
+ def disable_charging(self) -> None:
"""
Disable charging on all DUTs.
"""
@@ -121,7 +125,7 @@ class DutController:
except Exception as e:
logging.error(f"Failed to disable charging on {d.name}: {e}")
- def set_soc_limit(self, soc_limit: int):
+ def set_soc_limit(self, soc_limit: int) -> None:
"""
Set the state of charge (SoC) limit for all DUTs.
:param soc_limit: The SoC limit to set (0-100).
@@ -132,7 +136,7 @@ class DutController:
except Exception as e:
logging.error(f"Failed to set SoC limit on {d.name}: {e}")
- def all_duts_charged(self):
+ def all_duts_charged(self) -> bool:
all_dut_charged = True
@@ -149,7 +153,7 @@ class DutController:
return all_dut_charged
- def all_duts_discharged(self):
+ def all_duts_discharged(self) -> bool:
all_dut_dischargerd = True
@@ -174,7 +178,7 @@ class DutController:
return all_dut_dischargerd
- def any_dut_charged(self):
+ def any_dut_charged(self) -> bool:
for d in self.duts:
# Read power report
@@ -186,7 +190,7 @@ class DutController:
return False
- def any_dut_discharged(self):
+ def any_dut_discharged(self) -> bool:
for d in self.duts:
# Read power report
@@ -203,7 +207,7 @@ class DutController:
return False
- def set_backlight(self, value):
+ def set_backlight(self, value: int) -> None:
for d in self.duts:
try:
@@ -212,8 +216,13 @@ class DutController:
logging.error(f"Failed to set backlight on {d.name}: {e}")
def log_data(
- self, output_directory: Path, test_time_id, test_scenario, test_phase, temp
- ):
+ self,
+ output_directory: Path,
+ test_time_id: str,
+ test_scenario: str,
+ test_phase: str,
+ temp: float | int,
+ ) -> None:
# Log file name format:
# > <device_id_hash>.<time_identifier>.<test_scenario>.<temperarture>.csv
@@ -222,12 +231,12 @@ class DutController:
for d in self.duts:
d.log_data(output_directory, test_time_id, test_scenario, test_phase, temp)
- def close(self):
+ def close(self) -> None:
for d in self.duts:
try:
d.close()
except Exception as e:
logging.error(f"Failed to close DUT {d.name}: {e}")
- def __del__(self):
+ def __del__(self) -> None:
self.close()
diff --git a/tools/automatic_battery_tester/hardware_ctl/deditec/bs_weu_16.py b/tools/automatic_battery_tester/hardware_ctl/deditec/bs_weu_16.py
index 853efac4..436ead0f 100644
--- a/tools/automatic_battery_tester/hardware_ctl/deditec/bs_weu_16.py
+++ b/tools/automatic_battery_tester/hardware_ctl/deditec/bs_weu_16.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import logging
import signal
import socket
@@ -12,7 +14,9 @@ PIN_COUNT = 16 # Total number of pins on the Deditec BS-WEU-16 board
class DeditecBsWeu16:
- def __init__(self, ip: str = IP, port: int = PORT, timeout_seconds: int = 3):
+ def __init__(
+ self, ip: str = IP, port: int = PORT, timeout_seconds: int = 3
+ ) -> None:
self.ip = ip
self.port = port
@@ -49,7 +53,7 @@ class DeditecBsWeu16:
self.socket = None
return False
- def send_command(self, command: bytes):
+ def send_command(self, command: bytes) -> bool:
if self.socket is None:
logging.error("DeditecBsWeu16: send_command called but not connected.")
diff --git a/tools/automatic_battery_tester/hardware_ctl/gdm8351/gdm8351.py b/tools/automatic_battery_tester/hardware_ctl/gdm8351/gdm8351.py
index 95dc87dd..c72b150c 100644
--- a/tools/automatic_battery_tester/hardware_ctl/gdm8351/gdm8351.py
+++ b/tools/automatic_battery_tester/hardware_ctl/gdm8351/gdm8351.py
@@ -1,11 +1,12 @@
import time
+from pathlib import Path
import pyvisa
class GDM8351:
- def __init__(self):
+ def __init__(self) -> None:
self.rm = pyvisa.ResourceManager()
@@ -52,13 +53,15 @@ class GDM8351:
break
- def get_id(self):
+ def get_id(self) -> str:
if self.device is None or not self.device_connected:
raise Exception("Device not connected.")
return self.device.query("*IDN?")
- def configure_temperature_sensing(self, sensor_type="K", junction_temp_deg=29.0):
+ def configure_temperature_sensing(
+ self, sensor_type: str = "K", junction_temp_deg: float = 29.0
+ ) -> None:
if sensor_type not in ["K", "J", "T"]:
raise ValueError("Invalid sensor type. Use 'K', 'J', or 'T'.")
@@ -81,7 +84,7 @@ class GDM8351:
return
- def read_temperature(self):
+ def read_temperature(self) -> float:
if self.device is None or not self.device_connected:
raise Exception("Device not connected.")
@@ -91,7 +94,9 @@ class GDM8351:
except Exception as e:
raise Exception(f"Failed to read temperature: {e}")
- def log_temperature(self, output_directory, test_time_id, verbose=False):
+ def log_temperature(
+ self, output_directory: Path, test_time_id: str, verbose: bool = False
+ ) -> None:
# Log file name format:
# > external_temp.<time_identifier>.csv
@@ -116,7 +121,7 @@ class GDM8351:
if verbose:
print(f"GDM8351 temperature: {temp}°C")
- def close(self):
+ def close(self) -> None:
if self.device is not None and self.device_connected:
try:
self.device.close()
diff --git a/tools/automatic_battery_tester/hardware_ctl/relay_controller.py b/tools/automatic_battery_tester/hardware_ctl/relay_controller.py
index 9aa650db..203722f8 100644
--- a/tools/automatic_battery_tester/hardware_ctl/relay_controller.py
+++ b/tools/automatic_battery_tester/hardware_ctl/relay_controller.py
@@ -14,7 +14,7 @@ class RelayController:
DEDITEC_PORT = 9912
MAX_PIN = 16 # Max PIN index (1-16)
- def __init__(self, ip_address: str):
+ def __init__(self, ip_address: str) -> None:
"""
Initilize relay controller.
@@ -111,5 +111,5 @@ class RelayController:
return self.deditec.control_relay(pins_on=[pin], pins_off=[])
- def close(self):
+ def close(self) -> None:
pass
diff --git a/tools/automatic_battery_tester/main_tester.py b/tools/automatic_battery_tester/main_tester.py
index 76dcca51..7d3f5881 100644
--- a/tools/automatic_battery_tester/main_tester.py
+++ b/tools/automatic_battery_tester/main_tester.py
@@ -1,4 +1,5 @@
# main_tester.py
+from __future__ import annotations
import logging
import sys
@@ -41,7 +42,7 @@ console_handler.setLevel(logging.INFO)
logger.addHandler(console_handler)
-def load_config(config_path="test_config.toml") -> Optional[Dict[str, Any]]:
+def load_config(config_path: str = "test_config.toml") -> Optional[Dict[str, Any]]:
"""Load test configuration from TOML config file ."""
config_file = config_path
logging.info(f"Loading configuration file: {config_file}")
@@ -74,7 +75,7 @@ def load_config(config_path="test_config.toml") -> Optional[Dict[str, Any]]:
def run_test_cycle(
- config: dict,
+ config: dict[str, Any],
temp_c: float,
cycle_num: int,
test_mode: str,
@@ -141,7 +142,7 @@ def run_test_cycle(
return True
-def main():
+def main() -> None:
logging.info("==============================================")
logging.info(" Starting Automated Battery Cycle Tester ")
diff --git a/tools/automatic_battery_tester/single_capture.py b/tools/automatic_battery_tester/single_capture.py
index b6739b37..ee692df0 100644
--- a/tools/automatic_battery_tester/single_capture.py
+++ b/tools/automatic_battery_tester/single_capture.py
@@ -19,7 +19,7 @@ external thermocouple sensor connected to the GDM8351 multimeter.
"""
-def main():
+def main() -> None:
print("**********************************************************")
print(" DUT port selection ")
diff --git a/tools/automatic_battery_tester/test_logic/linear_scenario.py b/tools/automatic_battery_tester/test_logic/linear_scenario.py
index e7478eb4..441084f2 100644
--- a/tools/automatic_battery_tester/test_logic/linear_scenario.py
+++ b/tools/automatic_battery_tester/test_logic/linear_scenario.py
@@ -23,7 +23,9 @@ class ScenarioPhase(enum.Enum):
class LinearScenario(TestScenario):
- def __init__(self, discharge_load=100, relaxation_time_min=60):
+ def __init__(
+ self, discharge_load: int = 100, relaxation_time_min: int = 60
+ ) -> None:
# DUT use display backlight intensity to change its load (discharge
# current). Backlight intensity could be set in range of 0-255, but
@@ -38,7 +40,7 @@ class LinearScenario(TestScenario):
self.time_id = "0000000000"
self.previous_phase = ScenarioPhase.NOT_STARTED
- def setup(self, dut_controller: DutController):
+ def setup(self, dut_controller: DutController) -> None:
# Start with charging phase first, so connect the charger with relay
# and enable the charging.
@@ -56,7 +58,7 @@ class LinearScenario(TestScenario):
self.phase_start = time.time()
self.test_time_id = f"{time.strftime('%y%m%d%H%M')}"
- def run(self, dut_controller):
+ def run(self, dut_controller: DutController) -> bool:
if self.previous_phase != self.scenario_phase:
logging.info(f"Linear scenario entered {self.scenario_phase} phase.")
@@ -126,7 +128,9 @@ class LinearScenario(TestScenario):
# Relax
return False
- def log_data(self, dut_controller, output_directory: Path, temp):
+ def log_data(
+ self, dut_controller: DutController, output_directory: Path, temp: float
+ ) -> None:
dut_controller.log_data(
output_directory,
@@ -136,5 +140,5 @@ class LinearScenario(TestScenario):
temp,
)
- def teardown(self, dut_controller):
+ def teardown(self, dut_controller: DutController) -> None:
pass
diff --git a/tools/automatic_battery_tester/test_logic/random_wonder_scenario.py b/tools/automatic_battery_tester/test_logic/random_wonder_scenario.py
index 78e1e052..74e304fb 100644
--- a/tools/automatic_battery_tester/test_logic/random_wonder_scenario.py
+++ b/tools/automatic_battery_tester/test_logic/random_wonder_scenario.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import enum
import logging
import random
@@ -26,7 +28,7 @@ class ScenarioPhase(enum.Enum):
class RandomWonderScenario(TestScenario):
- def __init__(self, core_test_time=60, relaxation_time_min=60):
+ def __init__(self, core_test_time: int = 60, relaxation_time_min: int = 60) -> None:
self.relaxation_time_min = relaxation_time_min
self.phase_start = time.time()
@@ -40,7 +42,7 @@ class RandomWonderScenario(TestScenario):
self.time_id = "0000000000"
self.previous_phase = ScenarioPhase.NOT_STARTED
- def setup(self, dut_controller: DutController):
+ def setup(self, dut_controller: DutController) -> None:
# Start with charging phase first, so connect the charger with relay
# and enable the charging.
@@ -59,7 +61,7 @@ class RandomWonderScenario(TestScenario):
self.phase_start = time.time()
self.test_time_id = f"{time.strftime('%y%m%d%H%M')}"
- def run(self, dut_controller):
+ def run(self, dut_controller: DutController) -> bool:
if self.previous_phase != self.scenario_phase:
logging.info(f"Random Wonder scenario entered {self.scenario_phase} phase.")
@@ -222,7 +224,9 @@ class RandomWonderScenario(TestScenario):
# Relax
return False
- def log_data(self, dut_controller, output_directory: Path, temp):
+ def log_data(
+ self, dut_controller: DutController, output_directory: Path, temp: float | int
+ ) -> None:
dut_controller.log_data(
output_directory,
@@ -232,5 +236,5 @@ class RandomWonderScenario(TestScenario):
temp,
)
- def teardown(self, dut_controller):
+ def teardown(self, dut_controller: DutController) -> None:
pass
diff --git a/tools/automatic_battery_tester/test_logic/switching_scenario.py b/tools/automatic_battery_tester/test_logic/switching_scenario.py
index 7d3ec5ad..6699550a 100644
--- a/tools/automatic_battery_tester/test_logic/switching_scenario.py
+++ b/tools/automatic_battery_tester/test_logic/switching_scenario.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import enum
import logging
import time
@@ -23,7 +25,9 @@ class ScenarioPhase(enum.Enum):
class SwitchingScenario(TestScenario):
- def __init__(self, discharge_switch_cycle_min=5, relaxation_time_min=60):
+ def __init__(
+ self, discharge_switch_cycle_min: int = 5, relaxation_time_min: int = 60
+ ) -> None:
# DUT use display backlight intensity to change its load (discharge
# current). Backlight intensity could be set in range of 0-255, but
@@ -39,7 +43,7 @@ class SwitchingScenario(TestScenario):
self.test_time_id = "0000000000"
self.previous_phase = ScenarioPhase.NOT_STARTED
- def setup(self, dut_controller: DutController):
+ def setup(self, dut_controller: DutController) -> None:
# Start with charging phase first, so connect the charger with relay
# and enable the charging.
@@ -58,7 +62,7 @@ class SwitchingScenario(TestScenario):
self.phase_start = time.time()
self.test_time_id = f"{time.strftime('%y%m%d%H%M')}"
- def run(self, dut_controller):
+ def run(self, dut_controller: DutController) -> bool:
if self.previous_phase != self.scenario_phase:
logging.info(f"Switching scenario entered {self.scenario_phase} phase.")
@@ -140,7 +144,9 @@ class SwitchingScenario(TestScenario):
# Relax
return False
- def log_data(self, dut_controller, output_directory: Path, temp):
+ def log_data(
+ self, dut_controller: DutController, output_directory: Path, temp: float | int
+ ) -> None:
dut_controller.log_data(
output_directory,
@@ -150,5 +156,5 @@ class SwitchingScenario(TestScenario):
temp,
)
- def teardown(self, dut_controller):
+ def teardown(self, dut_controller: DutController) -> None:
pass
diff --git a/tools/automatic_battery_tester/test_logic/test_scenario.py b/tools/automatic_battery_tester/test_logic/test_scenario.py
index 7ac361d1..39da91aa 100644
--- a/tools/automatic_battery_tester/test_logic/test_scenario.py
+++ b/tools/automatic_battery_tester/test_logic/test_scenario.py
@@ -1,21 +1,28 @@
+from __future__ import annotations
+
from abc import ABC, abstractmethod
+from pathlib import Path
+
+from dut.dut_controller import DutController
class TestScenario(ABC):
"""Parent class for test scenarios."""
@abstractmethod
- def setup(self):
+ def setup(self, dut_controller: DutController) -> None:
pass
@abstractmethod
- def run(self):
+ def run(self, dut_controller: DutController) -> bool:
pass
@abstractmethod
- def teardown(self):
+ def teardown(self, dut_controller: DutController) -> None:
pass
@abstractmethod
- def log_data(self):
+ def log_data(
+ self, dut_controller: DutController, output_directory: Path, temp: float | int
+ ) -> None:
pass
diff --git a/tools/build_solana_templates.py b/tools/build_solana_templates.py
index 4c0e78b1..2ac83754 100755
--- a/tools/build_solana_templates.py
+++ b/tools/build_solana_templates.py
@@ -4,6 +4,7 @@ import os
import subprocess
import tempfile
from pathlib import Path
+from typing import Any
import click
from mako.template import Template
@@ -22,11 +23,11 @@ TEMPLATES = (
PROGRAMS_JSON = ROOT / "common" / "defs" / "solana" / "programs.json"
-def _silent_call(*args):
+def _silent_call(*args: Any) -> None:
subprocess.check_call(args, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
-def format(file: Path):
+def format(file: Path) -> None:
_silent_call("isort", file)
_silent_call("black", file)
_silent_call("flake8", file, "--config", ROOT / "setup.cfg")
@@ -51,8 +52,9 @@ def render_single(template_path: Path, programs: Munch) -> str:
@click.option(
"-c", "--check", is_flag=True, help="Check if the templates are up to date"
)
-def build_templates(check: bool):
+def build_templates(check: bool) -> None:
programs = munchify(json.loads(PROGRAMS_JSON.read_text()))
+ assert isinstance(programs, Munch)
prog_stat = PROGRAMS_JSON.stat()
all_ok = True
diff --git a/tools/bump-version.py b/tools/bump-version.py
index 55905be8..cf82a46e 100755
--- a/tools/bump-version.py
+++ b/tools/bump-version.py
@@ -1,8 +1,10 @@
#!/usr/bin/env python3
+from __future__ import annotations
import re
import subprocess
from pathlib import Path
+from typing import Any
import click
@@ -11,7 +13,7 @@ HEADER_LINE_RE = re.compile(r"^#define ([A-Z_]+) \S+$")
VERSION_FILE_LINE_RE = re.compile(r"^([A-Z_]+) = \S+$")
-def bump_header(filename: Path, **kwargs):
+def bump_header(filename: Path, **kwargs: Any) -> None:
result_lines = []
with open(filename, "r+") as fh:
@@ -29,7 +31,7 @@ def bump_header(filename: Path, **kwargs):
fh.write(line)
-def bump_version_file(filename: Path, **kwargs):
+def bump_version_file(filename: Path, **kwargs: Any) -> None:
result_lines = []
with open(filename, "r+") as fh:
@@ -47,11 +49,11 @@ def bump_version_file(filename: Path, **kwargs):
fh.write(line)
-def bump_python(subdir: Path, new_version: str):
+def bump_python(subdir: Path, new_version: str) -> None:
subprocess.check_call(["uv", "version", new_version], cwd=subdir)
-def hex_lit(version):
+def hex_lit(version: Any) -> str:
return rf'"\x{int(version):02X}"'
@@ -64,7 +66,7 @@ def hex_lit(version):
"version",
type=str,
)
-def cli(project, version):
+def cli(project: str | Path, version: str) -> None:
"""Bump version for given project (core, python, legacy/firmware,
legacy/bootloader, core/embed/projects/prodtest, nordic/trezor/trezor-ble).
"""
diff --git a/tools/changelog.py b/tools/changelog.py
index 82b324ab..f827812e 100755
--- a/tools/changelog.py
+++ b/tools/changelog.py
@@ -1,4 +1,5 @@
#!/usr/bin/env python3
+from __future__ import annotations
import datetime
import re
@@ -79,7 +80,7 @@ def linkify_changelog(changelog_file: Path, only_check: bool = False) -> bool:
return True
-def linkify_gh_diff(changelog_file: Path, tag_prefix: str):
+def linkify_gh_diff(changelog_file: Path, tag_prefix: str) -> None:
linkified = False
versions = []
result_lines = []
@@ -123,7 +124,7 @@ def current_date(project: Path) -> str:
return today.strftime(f"%-d{daysuffix} %B %Y")
-def filter_changelog(changelog_file: Path, internal_name: str):
+def filter_changelog(changelog_file: Path, internal_name: str) -> None:
def filter_line(line: str) -> str | None:
m = MODELS_RE.search(line)
if not m:
@@ -162,7 +163,7 @@ def _iter_fragments(project: Path) -> Iterator[Path]:
yield fragment
-def check_fragments_style(project: Path):
+def check_fragments_style(project: Path) -> None:
success = True
for fragment in _iter_fragments(project):
fragment_text = fragment.read_text().strip()
@@ -179,7 +180,7 @@ def check_fragments_style(project: Path):
click.echo(f"Changelog style OK: {project}")
-def fix_fragments_style(project: Path):
+def fix_fragments_style(project: Path) -> None:
for fragment in _iter_fragments(project):
fragment_text = fragment.read_text().rstrip()
if not fragment_text.endswith("."):
@@ -187,7 +188,7 @@ def fix_fragments_style(project: Path):
click.echo(f"Changelog '{fragment}' style fixed.")
-def generate_filtered(project: Path, changelog: Path):
+def generate_filtered(project: Path, changelog: Path) -> None:
if project.parts[-1] != "core":
return
@@ -198,19 +199,19 @@ def generate_filtered(project: Path, changelog: Path):
@click.group()
-def cli():
+def cli() -> None:
pass
@cli.command()
-def check():
+def check() -> None:
"""Check the style of all changelog fragments."""
for project in KNOWN_PROJECTS:
check_fragments_style(project)
@cli.command()
-def style():
+def style() -> None:
"""Fix the style of all changelog fragments."""
for project in KNOWN_PROJECTS:
fix_fragments_style(project)
@@ -241,7 +242,13 @@ def style():
is_flag=True,
help="Only regenerate the model-changelogs from the main one.",
)
-def generate(project, version, date, check, only_models):
+def generate(
+ project: Path,
+ version: str | None,
+ date: str | None,
+ check: bool,
+ only_models: bool,
+) -> None:
"""Generate changelog for given project (core, python, legacy/firmware,
legacy/bootloader).
diff --git a/tools/check_docs_summary.py b/tools/check_docs_summary.py
index 30c68fe2..b2ffd2ac 100755
--- a/tools/check_docs_summary.py
+++ b/tools/check_docs_summary.py
@@ -63,7 +63,7 @@ def print_result(filenames: Iterable[str]) -> None:
sys.exit(1)
-def main():
+def main() -> None:
re_md_link = re.compile(RE_MARKDOWN_LINK)
md_files_in_docs_dir = Path(DOCS_DIR).rglob("*.md")
diff --git a/tools/github_issues_to_csv.py b/tools/github_issues_to_csv.py
index 783f30c0..b38e899d 100644
--- a/tools/github_issues_to_csv.py
+++ b/tools/github_issues_to_csv.py
@@ -7,6 +7,7 @@ Currently writes all issues that have some Weight.
import argparse
import csv
import os.path
+from typing import Any
import requests
@@ -27,7 +28,7 @@ SEVERITIES = ("S1", "S2", "S3", "S4")
WEIGHTS = ("W0", "W1/2", "W1", "W2", "W3", "W5", "W8", "W13", "W20", "W40", "W100")
-def write_issues(r, csvout):
+def write_issues(r: requests.Response, csvout: Any) -> None:
"""Parses JSON response and writes to CSV."""
if r.status_code != 200:
raise Exception(r.status_code)
@@ -70,7 +71,7 @@ def write_issues(r, csvout):
)
-def get_issues(name):
+def get_issues(name: str) -> None:
"""Requests issues from GitHub API and writes to CSV file."""
url = f"https://api.github.com/repos/{name}/issues?state=all"
if token is not None:
diff --git a/tools/print-rust-stack-sizes.py b/tools/print-rust-stack-sizes.py
index f91a9ecb..35f6eef0 100755
--- a/tools/print-rust-stack-sizes.py
+++ b/tools/print-rust-stack-sizes.py
@@ -1,4 +1,5 @@
#!/usr/bin/env python3
+from __future__ import annotations
import subprocess
from pathlib import Path
@@ -16,7 +17,7 @@ FIRMWARE_ELF = ROOT / "core" / "build" / "firmware" / "firmware.elf"
elf = ELFFile(FIRMWARE_ELF.open("rb"))
-def load_address_map():
+def load_address_map() -> dict[int, str]:
"""Load address map from firmware ELF file using `nm`."""
out = subprocess.check_output(
args=["arm-none-eabi-nm", "--radix=d", "--demangle", FIRMWARE_ELF]
@@ -27,9 +28,10 @@ def load_address_map():
}
-def load_stack_sizes():
+def load_stack_sizes() -> list:
"""Load Rust stack sizes from firmware ELF section generated by `-Z emit-stack-sizes`."""
stack_sizes = elf.get_section_by_name(".stack_sizes")
+ assert stack_sizes is not None
Entries = GreedyRange(
Struct(
@@ -42,7 +44,7 @@ def load_stack_sizes():
@click.command()
-def main():
+def main() -> None:
"""Print Rust functions' stack size.
See https://blog.japaric.io/stack-analysis/ for more details.
diff --git a/tools/snippets/font_multiplier.py b/tools/snippets/font_multiplier.py
index 5cbb8e4a..9ffea8c6 100644
--- a/tools/snippets/font_multiplier.py
+++ b/tools/snippets/font_multiplier.py
@@ -95,7 +95,7 @@ def _index_to_point(index: int, width: int) -> Point:
return x, y
-def print_from_bits(width: int, height: int, bit_data: list[Bit]):
+def print_from_bits(width: int, height: int, bit_data: list[Bit]) -> None:
"""Print the glyph into terminal from bit data."""
for line_id in range(height):
line = bit_data[line_id * width : (line_id + 1) * width]
@@ -104,7 +104,7 @@ def print_from_bits(width: int, height: int, bit_data: list[Bit]):
print()
-def print_from_bytes(width: int, height: int, bytes_data: list[int]):
+def print_from_bytes(width: int, height: int, bytes_data: list[int]) -> None:
"""Print the glyph into terminal from byte data."""
bits_data = _bytes_to_bits(bytes_data, height * width)
print_from_bits(width, height, bits_data)
@@ -125,7 +125,7 @@ M_WIDTH = 7
# fmt: on
-def test_bits_to_bytes_and_back():
+def test_bits_to_bytes_and_back() -> None:
vectors = ( # height, width, bytes_data
(HEIGHT, K_WIDTH, K_GLYPH),
(HEIGHT, M_WIDTH, M_GLYPH),
@@ -136,11 +136,11 @@ def test_bits_to_bytes_and_back():
assert _bits_to_bytes(bits_data) == bytes_data
-def test_bit_to_bytes():
+def test_bit_to_bytes() -> None:
assert _bytes_to_bits(K_GLYPH, HEIGHT * K_WIDTH) == K_BITS
-def test_overall_magnify():
+def test_overall_magnify() -> None:
assert magnify_glyph_by_two(K_WIDTH, HEIGHT, K_GLYPH) == K_MAGNIFIED
diff --git a/tools/snippets/recalc_optiga_for_emulator.py b/tools/snippets/recalc_optiga_for_emulator.py
index 67917992..13a7bacd 100644
--- a/tools/snippets/recalc_optiga_for_emulator.py
+++ b/tools/snippets/recalc_optiga_for_emulator.py
@@ -9,15 +9,15 @@ from pyasn1.type.univ import BitString
from pyasn1_modules import rfc2459
-def load_certificate(data: bytes):
+def load_certificate(data: bytes) -> rfc2459.Certificate:
return decode(data, asn1Spec=rfc2459.Certificate())[0]
-def save_certificate(certificate) -> bytes:
+def save_certificate(certificate: rfc2459.Certificate) -> bytes:
return encode(certificate)
-def calculate_ecdsa_public_key():
+def calculate_ecdsa_public_key() -> ec.EllipticCurvePublicKey:
privkey_bytes = b"\x01" + b"\x00" * 31
private_key = ec.derive_private_key(
int.from_bytes(privkey_bytes, "big"), ec.SECP256R1()
@@ -26,7 +26,9 @@ def calculate_ecdsa_public_key():
return private_key.public_key()
-def replace_public_key(certificate, public_key):
+def replace_public_key(
+ certificate: rfc2459.Certificate, public_key: ec.EllipticCurvePublicKey
+) -> None:
public_key_bytes = public_key.public_bytes(
encoding=serialization.Encoding.X962,
format=serialization.PublicFormat.UncompressedPoint,
@@ -36,7 +38,7 @@ def replace_public_key(certificate, public_key):
)
-def main():
+def main() -> None:
in_cert = Path(sys.argv[1])
certificate = load_certificate(in_cert.read_bytes())
public_key = calculate_ecdsa_public_key()
diff --git a/tools/snippets/sign_tx.py b/tools/snippets/sign_tx.py
index 2dfa5746..45d01d96 100644
--- a/tools/snippets/sign_tx.py
+++ b/tools/snippets/sign_tx.py
@@ -21,7 +21,7 @@ from typing import Dict, List
import requests
from trezorlib import btc, messages
-from trezorlib.client import get_default_client
+from trezorlib.client import PASSPHRASE_ON_DEVICE, get_default_client
from trezorlib.debuglink import TrezorClientDebugLink
from trezorlib.tools import parse_path
from trezorlib.transport import enumerate_devices
@@ -119,7 +119,11 @@ if __name__ == "__main__":
raise RuntimeError("all outputs must be TxOutputType")
_, serialized_tx = btc.sign_tx(
- CLIENT, COIN, INPUTS, OUTPUTS, prev_txes=get_prev_txes(INPUTS)
+ CLIENT.get_session(passphrase=PASSPHRASE_ON_DEVICE),
+ COIN,
+ INPUTS,
+ OUTPUTS,
+ prev_txes=get_prev_txes(INPUTS),
)
print(80 * "-")
print(serialized_tx.hex())
diff --git a/tools/trezor-pylint-plugin/trezor_pylint_plugin.py b/tools/trezor-pylint-plugin/trezor_pylint_plugin.py
index 0cc97e2a..747308a6 100644
--- a/tools/trezor-pylint-plugin/trezor_pylint_plugin.py
+++ b/tools/trezor-pylint-plugin/trezor_pylint_plugin.py
@@ -1,7 +1,10 @@
+from __future__ import annotations
+
from astroid import nodes
from pylint.checkers import BaseChecker
from pylint.checkers.utils import check_messages
from pylint.interfaces import IAstroidChecker
+from pylint.lint import PyLinter
class AsyncAwaitableChecker(BaseChecker):
@@ -18,7 +21,7 @@ class AsyncAwaitableChecker(BaseChecker):
}
@check_messages("async-awaitable-return")
- def visit_asyncfunctiondef(self, node: nodes.AsyncFunctionDef):
+ def visit_asyncfunctiondef(self, node: nodes.AsyncFunctionDef) -> None:
# Check if the return type is explicitly an Awaitable
if node.returns and "Awaitable" in node.returns.as_string():
self.add_message("async-awaitable-return", node=node, args=(node.name,))
@@ -48,7 +51,7 @@ class InternalModelComparisonChecker(BaseChecker):
}
@staticmethod
- def _is_internal_model(node):
+ def _is_internal_model(node: nodes.NodeNG | None) -> bool:
return (
isinstance(node, nodes.Attribute)
and node.attrname == "INTERNAL_MODEL"
@@ -57,7 +60,7 @@ class InternalModelComparisonChecker(BaseChecker):
)
@check_messages("internal-model-tuple-comparison")
- def visit_compare(self, node: nodes.Compare):
+ def visit_compare(self, node: nodes.Compare) -> None:
if not self._is_internal_model(node.left):
return
if len(node.ops) != 1:
@@ -67,7 +70,7 @@ class InternalModelComparisonChecker(BaseChecker):
self.add_message("internal-model-tuple-comparison", node=node)
-def register(linter):
+def register(linter: PyLinter) -> None:
"""Required method to auto register this checker."""
linter.register_checker(AsyncAwaitableChecker(linter))
linter.register_checker(InternalModelComparisonChecker(linter))
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.