From 5b79af1206f7a88683eab903b8fa2fa87847335d Mon Sep 17 00:00:00 2001 From: Daniel Bast <2790401+dbast@users.noreply.github.com> Date: Fri, 5 Jul 2024 21:59:12 +0200 Subject: [PATCH 1/4] Enable code linting via pre-commit linting as in static code analysis to improve the overall code quality (this is not about code style!) pre-commit: The pre-commit framework became pretty widely used in recent years, especially in the Python world, where it originates from. It allows combine multiple hooks and has its own dependency management. There are many hooks for different routine checks like linting and code formatting, see also https://pre-commit.com/hooks.html. The hooks are configured in a file called .pre-commit-config.yaml and so don't pollute the requirements*.txt files. pre-commit can be added as git pre-commit hook via running `pre-commit install` or just be executed on cli (or IDE on every file change) via `pre-commit run --all`. Added this also as comments to the config file. With clever selections of hooks a runtime of <5 seconds can be achieved for a good developer experience, when running on every change. The config contains some standard hooks and ruff as Python code linter. ruff: https://github.com/astral-sh/ruff is proposed as Python linter as it is super fast (due to being implemented in Rust) and implements lots of lints/tests from flake8/bandit/pyupgrade/pylint and more and more big projects adopted it already. The elegant thing with ruff is the unified configuration via pyproject.toml, no matter what rule set gets activated or has to be partially ignored. This PR introduces pre-commit as concept and ruff with only the test category "F" (=pyflakes) and "T20" (=flake8-print) enabled to keep the amount of fixes reviewable. An added GH workflow runs it on every PR to check that there are no findings. The category "F" finds lots of things, that are fixed by this PR, like duplicated imports, un-used return-values, un-reachable code, un-used variables, hard to follow star imports etc. One exception are the type annotations in the controller.py, which are non-standard: Decided to add `# noqa` so that ruff ignores those and resolving those can be tried in a followup PR. Further PRs can add more hooks and/or enable more ruff rule categories, if sensible. --- .github/workflows/pre-commit.yml | 27 +++++++++++++++++++++++ .pre-commit-config.yaml | 37 ++++++++++++++++++++++++++++++++ README.md | 1 + pyproject.toml | 14 ++++++++++++ 4 files changed, 79 insertions(+) create mode 100644 .github/workflows/pre-commit.yml create mode 100644 .pre-commit-config.yaml diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml new file mode 100644 index 000000000..90a5f4b92 --- /dev/null +++ b/.github/workflows/pre-commit.yml @@ -0,0 +1,27 @@ +on: + push: + branches: + - main + - dev + pull_request: + +name: pre-commit + +concurrency: + # Concurrency group that uses the workflow name and PR number if available + # or commit SHA as a fallback. If a new build is triggered under that + # concurrency group while a previous build is running it will be canceled. + # Repeated pushes to a PR will cancel all previous builds, while multiple + # merges to main will not cancel. + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} + cancel-in-progress: true + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.10' + - uses: pre-commit/action@v3.0.1 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..c06fcbb45 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,37 @@ +# Apply to all files without commiting: +# pre-commit run --all-files +# Or enabled to run as git pre-commit hook: +# pre-commit install +# Update this file: +# pre-commit autoupdate +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + - id: check-added-large-files + - id: check-ast + - id: fix-byte-order-marker + - id: check-case-conflict + - id: check-merge-conflict + - id: check-toml + - id: check-yaml + - id: debug-statements + - id: detect-private-key + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.5.5 + hooks: + - id: ruff + args: [--fix, --show-fixes] + - repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks + rev: v2.14.0 + hooks: + - id: pretty-format-toml + args: [--autofix] + - repo: https://github.com/python-jsonschema/check-jsonschema + rev: 0.29.0 + hooks: + - id: check-github-workflows + - repo: meta + hooks: + - id: check-hooks-apply + - id: check-useless-excludes diff --git a/README.md b/README.md index 59fe0d805..143e6524d 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ [![CI](https://github.com/SeedSigner/seedsigner/actions/workflows/tests.yml/badge.svg)](https://github.com/SeedSigner/seedsigner/actions/workflows/tests.yml) [![Build](https://github.com/SeedSigner/seedsigner/actions/workflows/build.yml/badge.svg)](https://github.com/SeedSigner/seedsigner/actions/workflows/build.yml) +[![pre-commit](https://github.com/SeedSigner/seedsigner/actions/workflows/pre-commit.yml/badge.svg)](https://github.com/SeedSigner/seedsigner/actions/workflows/pre-commit.yml) The goal of SeedSigner is to lower the cost and complexity of Bitcoin multi-signature wallet use. To accomplish this goal, SeedSigner offers anyone the opportunity to build a verifiably air-gapped, stateless Bitcoin signing device using inexpensive, publicly available hardware components (usually < $50). SeedSigner helps users save with Bitcoin by assisting with trustless private key generation and multisignature (aka "multisig") wallet setup, and helps users transact with Bitcoin via a secure, air-gapped QR-exchange signing model. diff --git a/pyproject.toml b/pyproject.toml index a50a40c62..691cee5d6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,6 +60,20 @@ branch = true testpaths = ["tests"] log_level = "DEBUG" +[tool.ruff] +target-version = "py310" + +[tool.ruff.lint] +fixable = ["ALL"] +# List of rules https://docs.astral.sh/ruff/rules/ +select = ["F", "T20"] + +[tool.ruff.lint.per-file-ignores] +# vendored, so ignoring +"src/seedsigner/helpers/ur2/*" = ["F", "T20"] +"tests/**" = ["T20"] +"tools/*.py" = ["T20"] + [tool.setuptools] include-package-data = true From 06dd8ea4234b16c3fd7420210845cca1ee58b5f9 Mon Sep 17 00:00:00 2001 From: Daniel Bast <2790401+dbast@users.noreply.github.com> Date: Tue, 16 Jul 2024 16:51:01 +0200 Subject: [PATCH 2/4] Auto ruff fixes --- pyproject.toml | 2 +- src/seedsigner/gui/components.py | 2 +- src/seedsigner/gui/keyboard.py | 2 +- src/seedsigner/gui/renderer.py | 1 - src/seedsigner/gui/screens/psbt_screens.py | 12 ++++++------ src/seedsigner/gui/screens/scan_screens.py | 2 +- src/seedsigner/gui/screens/settings_screens.py | 5 ++--- src/seedsigner/hardware/pivideostream.py | 1 - src/seedsigner/helpers/embit_utils.py | 2 +- src/seedsigner/models/decode_qr.py | 18 +++++++++--------- src/seedsigner/models/encode_qr.py | 2 -- src/seedsigner/models/psbt_parser.py | 2 +- src/seedsigner/models/seed_storage.py | 2 +- src/seedsigner/views/scan_views.py | 5 ++--- src/seedsigner/views/seed_views.py | 13 ++++++------- src/seedsigner/views/tools_views.py | 5 ++--- tests/base.py | 2 +- tests/screenshot_generator/generator.py | 7 +++---- tests/test_bip85.py | 4 ---- tests/test_flows_psbt.py | 1 - tests/test_mnemonic_generation.py | 1 - tests/test_seed.py | 1 - tests/test_seedqr.py | 1 - tools/mnemonic.py | 6 +++--- 24 files changed, 41 insertions(+), 58 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 691cee5d6..a26482b1d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,8 +57,8 @@ skip_empty = true branch = true [tool.pytest.ini_options] -testpaths = ["tests"] log_level = "DEBUG" +testpaths = ["tests"] [tool.ruff] target-version = "py310" diff --git a/src/seedsigner/gui/components.py b/src/seedsigner/gui/components.py index 9193e451b..6a2aab994 100644 --- a/src/seedsigner/gui/components.py +++ b/src/seedsigner/gui/components.py @@ -344,7 +344,7 @@ def __post_init__(self): # Multiply for the number of lines plus the spacer total_text_height = self.text_height_above_baseline * len(self.text_lines) + self.line_spacing * (len(self.text_lines) - 1) - if not self.height_ignores_below_baseline and re.findall(f"[gjpqy]", self.text_lines[-1]["text"]): + if not self.height_ignores_below_baseline and re.findall("[gjpqy]", self.text_lines[-1]["text"]): # Last line has at least one char that dips below baseline total_text_height += self.text_height_below_baseline diff --git a/src/seedsigner/gui/keyboard.py b/src/seedsigner/gui/keyboard.py index 96f834415..9ef74134c 100644 --- a/src/seedsigner/gui/keyboard.py +++ b/src/seedsigner/gui/keyboard.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from PIL import Image, ImageDraw, ImageFont +from PIL import Image, ImageDraw from typing import Tuple from seedsigner.gui.components import Fonts, GUIConstants diff --git a/src/seedsigner/gui/renderer.py b/src/seedsigner/gui/renderer.py index 9534a7747..db0a4eb5b 100644 --- a/src/seedsigner/gui/renderer.py +++ b/src/seedsigner/gui/renderer.py @@ -1,7 +1,6 @@ from PIL import Image, ImageDraw from threading import Lock -from seedsigner.gui.components import Fonts, GUIConstants from seedsigner.hardware.ST7789 import ST7789 from seedsigner.models.singleton import ConfigurableSingleton diff --git a/src/seedsigner/gui/screens/psbt_screens.py b/src/seedsigner/gui/screens/psbt_screens.py index 36a2b8952..347054cd7 100644 --- a/src/seedsigner/gui/screens/psbt_screens.py +++ b/src/seedsigner/gui/screens/psbt_screens.py @@ -7,8 +7,8 @@ from seedsigner.gui.renderer import Renderer from seedsigner.models.threads import BaseThread -from .screen import ButtonListScreen, WarningScreen -from ..components import (BtcAmount, Button, Icon, FontAwesomeIconConstants, IconTextLine, FormattedAddress, GUIConstants, Fonts, SeedSignerIconConstants, TextArea, +from .screen import ButtonListScreen +from ..components import (BtcAmount, Icon, FontAwesomeIconConstants, IconTextLine, FormattedAddress, GUIConstants, Fonts, SeedSignerIconConstants, TextArea, calc_bezier_curve, linear_interp) @@ -139,11 +139,11 @@ def truncate_destination_addr(addr): destination_column.append(truncate_destination_addr("self-transfer")) else: # destination_column.append(f"{len(self.destination_addresses)} recipients") - destination_column.append(f"recipient 1") - destination_column.append(f"[ ... ]") + destination_column.append("recipient 1") + destination_column.append("[ ... ]") destination_column.append(f"recipient {len(self.destination_addresses) + self.num_self_transfer_outputs}") - destination_column.append(f"fee") + destination_column.append("fee") if self.has_op_return: destination_column.append("OP_RETURN") @@ -562,7 +562,7 @@ def render_amount(cur_y, amount_str, info_text, info_text_color=GUIConstants.BOD render_amount( cur_y, f"-{self.fee_amount}", - info_text=f""" fee""", + info_text=""" fee""", ) cur_y += digits_height + GUIConstants.BODY_LINE_SPACING * ssf diff --git a/src/seedsigner/gui/screens/scan_screens.py b/src/seedsigner/gui/screens/scan_screens.py index e1af8e157..239c01b1c 100644 --- a/src/seedsigner/gui/screens/scan_screens.py +++ b/src/seedsigner/gui/screens/scan_screens.py @@ -10,7 +10,7 @@ from seedsigner.models.threads import BaseThread, ThreadsafeCounter from .screen import BaseScreen -from ..components import GUIConstants, Fonts, SeedSignerIconConstants +from ..components import GUIConstants, Fonts diff --git a/src/seedsigner/gui/screens/settings_screens.py b/src/seedsigner/gui/screens/settings_screens.py index 55fa5dd00..7c4093d8d 100644 --- a/src/seedsigner/gui/screens/settings_screens.py +++ b/src/seedsigner/gui/screens/settings_screens.py @@ -3,10 +3,9 @@ from dataclasses import dataclass from PIL.ImageOps import autocontrast from typing import List -from seedsigner.gui.components import Button, CheckboxButton, CheckedSelectionButton, FontAwesomeIconConstants, Fonts, GUIConstants, Icon, IconButton, IconTextLine, TextArea -from seedsigner.gui.screens.scan_screens import ScanScreen +from seedsigner.gui.components import Button, CheckboxButton, CheckedSelectionButton, FontAwesomeIconConstants, Fonts, GUIConstants, Icon, IconButton, TextArea -from seedsigner.gui.screens.screen import BaseScreen, BaseTopNavScreen, ButtonListScreen +from seedsigner.gui.screens.screen import BaseTopNavScreen, ButtonListScreen from seedsigner.hardware.buttons import HardwareButtonsConstants from seedsigner.hardware.camera import Camera from seedsigner.models.settings import SettingsConstants diff --git a/src/seedsigner/hardware/pivideostream.py b/src/seedsigner/hardware/pivideostream.py index 06a1ebb7d..b1a94a4ba 100644 --- a/src/seedsigner/hardware/pivideostream.py +++ b/src/seedsigner/hardware/pivideostream.py @@ -3,7 +3,6 @@ from picamera.array import PiRGBArray from picamera import PiCamera from threading import Thread -import time logger = logging.getLogger(__name__) diff --git a/src/seedsigner/helpers/embit_utils.py b/src/seedsigner/helpers/embit_utils.py index 7e260aa43..52d00cc43 100644 --- a/src/seedsigner/helpers/embit_utils.py +++ b/src/seedsigner/helpers/embit_utils.py @@ -44,7 +44,7 @@ def get_standard_derivation_path(network: str = SettingsConstants.MAINNET, walle elif wallet_type == SettingsConstants.MULTISIG: if script_type == SettingsConstants.LEGACY_P2PKH: - return f"m/45'" #BIP45 + return "m/45'" #BIP45 elif script_type == SettingsConstants.NESTED_SEGWIT: return f"m/48'/{network_path}/0'/1'" elif script_type == SettingsConstants.NATIVE_SEGWIT: diff --git a/src/seedsigner/models/decode_qr.py b/src/seedsigner/models/decode_qr.py index 4ac166423..20f989fae 100644 --- a/src/seedsigner/models/decode_qr.py +++ b/src/seedsigner/models/decode_qr.py @@ -423,7 +423,7 @@ def detect_segment_type(s, wordlist_language_code=None): # print(bitstream) return QRType.SEED__COMPACTSEEDQR - except Exception as e: + except Exception: # Couldn't extract byte data; assume it's not a byte format pass @@ -555,7 +555,7 @@ def multisig_setup_file_to_descriptor(text) -> str: m = int(match.group(1)) n = int(match.group(2)) except: - raise Exception(f"Policy line not supported") + raise Exception("Policy line not supported") elif label == 'derivation': derivation = value elif label == 'format': @@ -569,16 +569,16 @@ def multisig_setup_file_to_descriptor(text) -> str: x += 1 if None in xpubs or len(xpubs) != n: - raise Exception(f"bad or missing xpub") + raise Exception("bad or missing xpub") if m <= 0 or m > 9 or n <= 0 or n > 9: - raise Exception(f"bad or missing policy") + raise Exception("bad or missing policy") if len(derivation) == 0: - raise Exception(f"bad or missing derivation path") + raise Exception("bad or missing derivation path") if script_type not in ['p2wsh', 'p2sh-p2wsh', 'p2wsh-p2sh']: - raise Exception(f"bad or missing script format") + raise Exception("bad or missing script format") # create descriptor string @@ -786,7 +786,7 @@ def add(self, segment, qr_type=QRType.SEED__SEEDQR): return DecodeQRStatus.COMPLETE else: return DecodeQRStatus.INVALID - except Exception as e: + except Exception: return DecodeQRStatus.INVALID if qr_type == QRType.SEED__COMPACTSEEDQR: @@ -814,7 +814,7 @@ def add(self, segment, qr_type=QRType.SEED__SEEDQR): self.complete = True self.collected_segments = 1 return DecodeQRStatus.COMPLETE - except Exception as e: + except Exception: return DecodeQRStatus.INVALID elif qr_type == QRType.SEED__FOUR_LETTER_MNEMONIC: @@ -837,7 +837,7 @@ def add(self, segment, qr_type=QRType.SEED__SEEDQR): self.complete = True self.collected_segments = 1 return DecodeQRStatus.COMPLETE - except Exception as e: + except Exception: return DecodeQRStatus.INVALID else: diff --git a/src/seedsigner/models/encode_qr.py b/src/seedsigner/models/encode_qr.py index 65a8f5d1f..73e2514f5 100644 --- a/src/seedsigner/models/encode_qr.py +++ b/src/seedsigner/models/encode_qr.py @@ -5,8 +5,6 @@ from binascii import hexlify from dataclasses import dataclass from typing import List -from embit import bip32 -from embit.networks import NETWORKS from embit.psbt import PSBT from seedsigner.helpers.ur2.ur_encoder import UREncoder from seedsigner.helpers.ur2.ur import UR diff --git a/src/seedsigner/models/psbt_parser.py b/src/seedsigner/models/psbt_parser.py index 7aa995388..1224df044 100644 --- a/src/seedsigner/models/psbt_parser.py +++ b/src/seedsigner/models/psbt_parser.py @@ -70,7 +70,7 @@ def _set_root(self): def parse(self): if self.psbt is None: - logger.info(f"self.psbt is None!!") + logger.info("self.psbt is None!!") return False if not self.seed: diff --git a/src/seedsigner/models/seed_storage.py b/src/seedsigner/models/seed_storage.py index 85feb49cb..cb4342e41 100644 --- a/src/seedsigner/models/seed_storage.py +++ b/src/seedsigner/models/seed_storage.py @@ -38,7 +38,7 @@ def clear_pending_seed(self): def validate_mnemonic(self, mnemonic: List[str]) -> bool: try: Seed(mnemonic=mnemonic) - except InvalidSeedException as e: + except InvalidSeedException: return False return True diff --git a/src/seedsigner/views/scan_views.py b/src/seedsigner/views/scan_views.py index 1b923efa0..a8130114d 100644 --- a/src/seedsigner/views/scan_views.py +++ b/src/seedsigner/views/scan_views.py @@ -3,12 +3,11 @@ from embit.descriptor import Descriptor -from seedsigner.gui.screens.screen import RET_CODE__BACK_BUTTON from seedsigner.models.decode_qr import DecodeQR from seedsigner.models.seed import Seed from seedsigner.models.settings import SettingsConstants from seedsigner.views.settings_views import SettingsIngestSettingsQRView -from seedsigner.views.view import BackStackView, ErrorView, MainMenuView, NotYetImplementedView, OptionDisabledView, View, Destination +from seedsigner.views.view import BackStackView, ErrorView, MainMenuView, NotYetImplementedView, View, Destination logger = logging.getLogger(__name__) @@ -184,7 +183,7 @@ def is_valid_qr_type(self): class ScanSeedQRView(ScanView): instructions_text = "Scan SeedQR" - invalid_qr_type_message = f"Expected a SeedQR" + invalid_qr_type_message = "Expected a SeedQR" @property def is_valid_qr_type(self): diff --git a/src/seedsigner/views/seed_views.py b/src/seedsigner/views/seed_views.py index 9483c1119..a4843b876 100644 --- a/src/seedsigner/views/seed_views.py +++ b/src/seedsigner/views/seed_views.py @@ -15,7 +15,6 @@ from seedsigner.gui.screens import (RET_CODE__BACK_BUTTON, ButtonListScreen, WarningScreen, DireWarningScreen, seed_screens) from seedsigner.gui.screens.screen import LargeIconStatusScreen, QRDisplayScreen -from seedsigner.helpers import embit_utils from seedsigner.models.decode_qr import DecodeQR from seedsigner.models.encode_qr import CompactSeedQrEncoder, GenericStaticQrEncoder, SeedQrEncoder, SpecterXPubQrEncoder, StaticXpubQrEncoder, UrXpubQrEncoder from seedsigner.models.psbt_parser import PSBTParser @@ -289,7 +288,7 @@ def run(self): WarningScreen, title="Invalid Mnemonic!", status_headline=None, - text=f"Checksum failure; not a valid seed phrase.", + text="Checksum failure; not a valid seed phrase.", show_back_button=False, button_data=button_data, ) @@ -376,7 +375,7 @@ def run(self): WarningScreen, title="Discard passphrase?", status_headline=None, - text=f"Your current passphrase entry will be erased", + text="Your current passphrase entry will be erased", show_back_button=False, button_data=button_data, ) @@ -486,7 +485,7 @@ def run(self): WarningScreen, title="Electrum warning", status_headline=None, - text=f"Some features are disabled for Electrum seeds.", + text="Some features are disabled for Electrum seeds.", show_back_button=False, ) @@ -1178,7 +1177,7 @@ def run(self): DireWarningScreen( title="BIP-85 Index Error", show_back_button=False, - status_headline=f"Invalid Child Index", + status_headline="Invalid Child Index", text=f"BIP-85 Child Index must be between 0 and {2**31-1}.", button_data=["Try Again"] ).display() @@ -1318,7 +1317,7 @@ def run(self): selected_menu_num = DireWarningScreen( title="Verification Error", show_back_button=False, - status_headline=f"Wrong Word!", + status_headline="Wrong Word!", text=f"Word #{self.cur_index + 1} is not \"{self.wrong_word}\"!", button_data=button_data, ).display() @@ -2034,7 +2033,7 @@ def __init__(self, derivation_path: str, message: str): # calculate the actual receive address addr_format = embit_utils.parse_derivation_path(derivation_path) if not addr_format["clean_match"]: - self.set_redirect(Destination(NotYetImplementedView, view_args=dict(text=f"Signing messages for custom derivation paths not supported"))) + self.set_redirect(Destination(NotYetImplementedView, view_args=dict(text="Signing messages for custom derivation paths not supported"))) self.controller.resume_main_flow = None return diff --git a/src/seedsigner/views/tools_views.py b/src/seedsigner/views/tools_views.py index eabb1171c..8ba7e92f2 100644 --- a/src/seedsigner/views/tools_views.py +++ b/src/seedsigner/views/tools_views.py @@ -1,4 +1,3 @@ -from dataclasses import dataclass import hashlib import logging import os @@ -10,7 +9,7 @@ from seedsigner.controller import Controller from seedsigner.gui.components import FontAwesomeIconConstants, GUIConstants, SeedSignerIconConstants -from seedsigner.gui.screens import (RET_CODE__BACK_BUTTON, ButtonListScreen, WarningScreen) +from seedsigner.gui.screens import (RET_CODE__BACK_BUTTON, ButtonListScreen) from seedsigner.gui.screens.tools_screens import (ToolsCalcFinalWordDoneScreen, ToolsCalcFinalWordFinalizePromptScreen, ToolsCalcFinalWordScreen, ToolsCoinFlipEntryScreen, ToolsDiceEntropyEntryScreen, ToolsImageEntropyFinalImageScreen, ToolsImageEntropyLivePreviewScreen, ToolsAddressExplorerAddressTypeScreen) @@ -281,7 +280,7 @@ def run(self): num_entropy_bits = 3 COIN_FLIPS = "Coin flip entropy" - SELECT_WORD = f"Word selection entropy" + SELECT_WORD = "Word selection entropy" ZEROS = "Finalize with zeros" button_data = [COIN_FLIPS, SELECT_WORD, ZEROS] diff --git a/tests/base.py b/tests/base.py index 100ac7413..09dc494f8 100644 --- a/tests/base.py +++ b/tests/base.py @@ -16,7 +16,7 @@ from seedsigner.gui.screens.screen import RET_CODE__BACK_BUTTON, RET_CODE__POWER_BUTTON from seedsigner.hardware.microsd import MicroSD from seedsigner.models.settings import Settings -from seedsigner.views.view import Destination, MainMenuView, UnhandledExceptionView, View +from seedsigner.views.view import Destination, MainMenuView, View import logging logger = logging.getLogger(__name__) diff --git a/tests/screenshot_generator/generator.py b/tests/screenshot_generator/generator.py index 4c0c092a8..ec04a224e 100644 --- a/tests/screenshot_generator/generator.py +++ b/tests/screenshot_generator/generator.py @@ -3,14 +3,13 @@ import random import sys import time -from unittest.mock import Mock, patch, MagicMock +from unittest.mock import Mock, MagicMock from seedsigner.helpers import embit_utils from embit import compact from embit.psbt import PSBT, OutputScope from embit.script import Script -from seedsigner.helpers import embit_utils from seedsigner.models.psbt_parser import OPCODES, PSBTParser @@ -289,7 +288,7 @@ def add_op_return_to_psbt(psbt: PSBT, raw_payload_data: bytes): ] } - readme = f"""# SeedSigner Screenshots\n""" + readme = """# SeedSigner Screenshots\n""" def screencap_view(view_cls: View, view_args: dict = {}, view_name: str = None, toast_thread: BaseToastOverlayManagerThread = None): if not view_name: @@ -324,7 +323,7 @@ def screencap_view(view_cls: View, view_args: dict = {}, view_name: str = None, readme += "\n\n---\n\n" readme += f"## {section_name}\n\n" readme += """""" - readme += f"""
\n""" + readme += """
\n""" for screenshot in screenshot_list: if type(screenshot) == tuple: if len(screenshot) == 2: diff --git a/tests/test_bip85.py b/tests/test_bip85.py index 737be5697..a9e1daf7a 100644 --- a/tests/test_bip85.py +++ b/tests/test_bip85.py @@ -1,9 +1,5 @@ -import pytest -from unittest.mock import MagicMock from seedsigner.models.seed import Seed -from embit import bip39 -from seedsigner.models.settings import SettingsConstants diff --git a/tests/test_flows_psbt.py b/tests/test_flows_psbt.py index 964b0d67b..307d4faea 100644 --- a/tests/test_flows_psbt.py +++ b/tests/test_flows_psbt.py @@ -1,6 +1,5 @@ from base import FlowTest, FlowStep -from seedsigner.controller import Controller from seedsigner.views.view import MainMenuView from seedsigner.views import scan_views, seed_views, psbt_views from seedsigner.models.settings import SettingsConstants diff --git a/tests/test_mnemonic_generation.py b/tests/test_mnemonic_generation.py index a1f46e85d..4cb548330 100644 --- a/tests/test_mnemonic_generation.py +++ b/tests/test_mnemonic_generation.py @@ -3,7 +3,6 @@ from embit import bip39 from seedsigner.helpers import mnemonic_generation -from seedsigner.models.settings_definition import SettingsConstants diff --git a/tests/test_seed.py b/tests/test_seed.py index 4dd8af930..68a7657db 100644 --- a/tests/test_seed.py +++ b/tests/test_seed.py @@ -1,7 +1,6 @@ import pytest from seedsigner.models.seed import InvalidSeedException, Seed, ElectrumSeed -from seedsigner.models.settings import SettingsConstants # TODO: Change TAB indents to SPACE diff --git a/tests/test_seedqr.py b/tests/test_seedqr.py index d792683c1..60c3db4df 100644 --- a/tests/test_seedqr.py +++ b/tests/test_seedqr.py @@ -4,7 +4,6 @@ from seedsigner.models.decode_qr import DecodeQR, DecodeQRStatus from seedsigner.models.encode_qr import SeedQrEncoder, CompactSeedQrEncoder from seedsigner.models.qr_type import QRType -from seedsigner.models.seed import Seed diff --git a/tools/mnemonic.py b/tools/mnemonic.py index 28490e943..dbf861615 100644 --- a/tools/mnemonic.py +++ b/tools/mnemonic.py @@ -142,7 +142,7 @@ entropy += f" {final_word}" elif final_entropy_method == '2': - final_word = input(f""" Enter the final word: """) + final_word = input(""" Enter the final word: """) if final_word not in WORDLIST__ENGLISH: print(f"Invalid word: {final_word}") exit(1) @@ -164,6 +164,6 @@ print(f"\tEntropy: {entropy}\n") if method == "dice": - print(f"""\tVerify at iancoleman.io/bip39 or bitcoiner.guide/seed using "Base 10" or "Hex" mode.\n""") + print("""\tVerify at iancoleman.io/bip39 or bitcoiner.guide/seed using "Base 10" or "Hex" mode.\n""") elif method == "coins": - print(f"""\tVerify at iancoleman.io/bip39 or bitcoiner.guide/seed using "Binary" mode.\n""") + print("""\tVerify at iancoleman.io/bip39 or bitcoiner.guide/seed using "Binary" mode.\n""") From 3166b6c926ea837017666b55794cd8b3253b0334 Mon Sep 17 00:00:00 2001 From: Daniel Bast <2790401+dbast@users.noreply.github.com> Date: Mon, 15 Jul 2024 10:04:49 +0200 Subject: [PATCH 3/4] Manual fixes --- src/seedsigner/controller.py | 2 +- src/seedsigner/gui/__init__.py | 4 +++- src/seedsigner/gui/components.py | 3 +-- src/seedsigner/gui/keyboard.py | 8 ++++---- src/seedsigner/gui/screens/__init__.py | 2 +- src/seedsigner/gui/screens/psbt_screens.py | 10 +++++----- src/seedsigner/gui/screens/screen.py | 2 +- src/seedsigner/gui/screens/seed_screens.py | 6 +++--- src/seedsigner/views/__init__.py | 4 +++- src/seedsigner/views/screensaver.py | 2 +- src/seedsigner/views/seed_views.py | 6 +++--- src/seedsigner/views/settings_views.py | 3 ++- src/seedsigner/views/tools_views.py | 2 +- src/seedsigner/views/view.py | 4 ++-- tests/test_controller.py | 2 +- tests/test_decodepsbtqr.py | 6 +++--- tests/test_embit_utils.py | 2 +- tests/test_flows.py | 2 +- tests/test_flows_seed.py | 4 ++-- tests/test_psbt_parser.py | 2 +- 20 files changed, 40 insertions(+), 36 deletions(-) diff --git a/src/seedsigner/controller.py b/src/seedsigner/controller.py index 6243955ff..5423073f0 100644 --- a/src/seedsigner/controller.py +++ b/src/seedsigner/controller.py @@ -60,7 +60,7 @@ def run(self): def time_import(module_name): last = time.time() import_module(module_name) - # print(time.time() - last, module_name) + logger.debug(f"Importing {module_name} took {time.time() - last} seconds") time_import('embit') time_import('seedsigner.helpers.embit_utils') diff --git a/src/seedsigner/gui/__init__.py b/src/seedsigner/gui/__init__.py index 05667487c..6fa8896dc 100644 --- a/src/seedsigner/gui/__init__.py +++ b/src/seedsigner/gui/__init__.py @@ -1 +1,3 @@ -from .renderer import Renderer \ No newline at end of file +from .renderer import Renderer + +__all__ = [Renderer] diff --git a/src/seedsigner/gui/components.py b/src/seedsigner/gui/components.py index 6a2aab994..ec6336b9b 100644 --- a/src/seedsigner/gui/components.py +++ b/src/seedsigner/gui/components.py @@ -3,7 +3,6 @@ import os import pathlib import re -from time import time from dataclasses import dataclass from decimal import Decimal @@ -1352,7 +1351,7 @@ def reflow_text_for_width(text: str, # We have to figure out if and where to make line breaks in the text so that it # fits in its bounding rect (plus accounting for edge padding) using its given # font. - start = time() + # start = time() font = Fonts.get_font(font_name=font_name, size=font_size) # Measure from left baseline ("ls") (left, top, full_text_width, bottom) = font.getbbox(text, anchor="ls") diff --git a/src/seedsigner/gui/keyboard.py b/src/seedsigner/gui/keyboard.py index 9ef74134c..ad80293b8 100644 --- a/src/seedsigner/gui/keyboard.py +++ b/src/seedsigner/gui/keyboard.py @@ -318,7 +318,7 @@ def get_key_at(self, index_x, index_y): return None effective_index = 0 - key = None + # key = None for cur_key in self.keys[index_y]: if index_x >= effective_index and index_x < effective_index + cur_key.size: return cur_key @@ -552,7 +552,7 @@ def render(self, cur_text=None, cursor_position=None): if self.cursor_mode == TextEntryDisplay.CURSOR_MODE__BLOCK: cursor_block_width = 18 - cursor_block_height = 33 + # cursor_block_height = 33 # Draw n-1 of the selected letters (left, top, right, bottom) = self.font.getbbox(self.cur_text[:-1], anchor="ls") @@ -592,7 +592,7 @@ def render(self, cur_text=None, cursor_position=None): # The entire cur_text plus the cursor bar fits self.text_offset = 3 + cursor_bar_serif_half_width left, top, right, bottom = self.font.getbbox(self.cur_text[:cursor_position]) - tw_left, th = right - left, bottom - top + tw_left, _ = right - left, bottom - top cursor_bar_x = self.text_offset + tw_left else: @@ -601,7 +601,7 @@ def render(self, cur_text=None, cursor_position=None): # Is the cursor at either extreme? left, top, right, bottom = self.font.getbbox(self.cur_text[:cursor_position]) - tw_left, th = right - left, bottom - top + tw_left, _ = right - left, bottom - top if self.text_offset + tw_left + cursor_bar_serif_half_width + 3 >= self.width: # Cursor is at the extreme right; have to push the full tw_right off diff --git a/src/seedsigner/gui/screens/__init__.py b/src/seedsigner/gui/screens/__init__.py index c6de8b0c6..b38a5b344 100644 --- a/src/seedsigner/gui/screens/__init__.py +++ b/src/seedsigner/gui/screens/__init__.py @@ -1 +1 @@ -from .screen import * \ No newline at end of file +# from .screen import * diff --git a/src/seedsigner/gui/screens/psbt_screens.py b/src/seedsigner/gui/screens/psbt_screens.py index 347054cd7..da07bcdd1 100644 --- a/src/seedsigner/gui/screens/psbt_screens.py +++ b/src/seedsigner/gui/screens/psbt_screens.py @@ -100,7 +100,7 @@ def __post_init__(self): max_inputs_text_width = 0 for input in inputs_column: left, top, right, bottom = font.getbbox(input) - tw, th = right - left, bottom - top + tw, _ = right - left, bottom - top max_inputs_text_width = max(tw, max_inputs_text_width) # Given how wide we want our curves on each side to be... @@ -155,7 +155,7 @@ def truncate_destination_addr(addr): max_destination_text_width = 0 for destination in destination_column: left, top, right, bottom = font.getbbox(destination) - tw, th = right - left, bottom - top + tw, _ = right - left, bottom - top max_destination_text_width = max(tw, max_destination_text_width) return (max_destination_text_width, destination_column) @@ -202,7 +202,7 @@ def truncate_destination_addr(addr): for input in inputs_column: # Calculate right-justified input display left, top, right, bottom = font.getbbox(input) - tw, th = right - left, bottom - top + tw, _ = right - left, bottom - top cur_x = inputs_x + max_inputs_text_width - tw draw.text( (cur_x, inputs_y), @@ -530,9 +530,9 @@ def render_amount(cur_y, amount_str, info_text, info_text_color=GUIConstants.BOD mid_zone = display_str[-6:-3] end_zone = display_str[-3:] left, top, right, bottom = fixed_width_font.getbbox(main_zone) - main_zone_width, th = right - left, bottom - top + main_zone_width, _ = right - left, bottom - top left, top, right, bottom = fixed_width_font.getbbox(end_zone) - mid_zone_width, th = right - left, bottom - top + mid_zone_width, _ = right - left, bottom - top draw.text((0, cur_y), text=main_zone, font=fixed_width_font, fill=GUIConstants.BODY_FONT_COLOR) draw.text((main_zone_width + digit_group_spacing, cur_y), text=mid_zone, font=fixed_width_font, fill=secondary_digit_color) draw.text((main_zone_width + digit_group_spacing + mid_zone_width + digit_group_spacing, cur_y), text=end_zone, font=fixed_width_font, fill=tertiary_digit_color) diff --git a/src/seedsigner/gui/screens/screen.py b/src/seedsigner/gui/screens/screen.py index a77997ab2..ef48f2c00 100644 --- a/src/seedsigner/gui/screens/screen.py +++ b/src/seedsigner/gui/screens/screen.py @@ -344,7 +344,7 @@ def __post_init__(self): self.down_arrow_img = Image.new("RGBA", size=(2 * self.arrow_half_width, 8), color="black") self.down_arrow_img_y = self.canvas_height - 16 + 2 arrow_draw = ImageDraw.Draw(self.down_arrow_img) - center_x = int(self.canvas_width / 2) + # center_x = int(self.canvas_width / 2) arrow_draw.line((self.arrow_half_width, 7, 0, 1), fill=GUIConstants.BUTTON_FONT_COLOR) arrow_draw.line((self.arrow_half_width, 7, 2 * self.arrow_half_width, 1), fill=GUIConstants.BUTTON_FONT_COLOR) diff --git a/src/seedsigner/gui/screens/seed_screens.py b/src/seedsigner/gui/screens/seed_screens.py index 64fb7ea98..8972cd0e6 100644 --- a/src/seedsigner/gui/screens/seed_screens.py +++ b/src/seedsigner/gui/screens/seed_screens.py @@ -177,7 +177,7 @@ def render_possible_matches(self, highlight_word=None): highlighted_row = 3 num_possible_rows = 11 - y = self.highlighted_row_y - GUIConstants.LIST_ITEM_PADDING - 3 * self.matches_list_row_height + # y = self.highlighted_row_y - GUIConstants.LIST_ITEM_PADDING - 3 * self.matches_list_row_height if not highlight_word: list_starting_index = self.selected_possible_words_index - highlighted_row @@ -1189,8 +1189,8 @@ def __post_init__(self): msg = "click to exit" font = Fonts.get_font(GUIConstants.BODY_FONT_NAME, GUIConstants.BODY_FONT_SIZE) (left, top, right, bottom) = font.getbbox(msg, anchor="ls") - msg_height = -1 * top - msg_width = right + # msg_height = -1 * top + # msg_width = right # draw.rectangle( # ( # int((self.canvas_width - msg_width)/2 - GUIConstants.COMPONENT_PADDING), diff --git a/src/seedsigner/views/__init__.py b/src/seedsigner/views/__init__.py index a78d84db3..98ae81b58 100644 --- a/src/seedsigner/views/__init__.py +++ b/src/seedsigner/views/__init__.py @@ -1 +1,3 @@ -from .view import * # base class has to be first +from .view import MainMenuView, BackStackView # base class has to be first + +__all__ = [MainMenuView, BackStackView] diff --git a/src/seedsigner/views/screensaver.py b/src/seedsigner/views/screensaver.py index 84476da47..d06dd60cc 100644 --- a/src/seedsigner/views/screensaver.py +++ b/src/seedsigner/views/screensaver.py @@ -136,7 +136,7 @@ def start(self): # Store the current screen in order to restore it later self.last_screen = self.renderer.canvas.copy() - screensaver_start = int(time.time() * 1000) + # screensaver_start = int(time.time() * 1000) # Screensaver must block any attempts to use the Renderer in another thread so it # never gives up the lock until it returns. diff --git a/src/seedsigner/views/seed_views.py b/src/seedsigner/views/seed_views.py index a4843b876..1c3083ba3 100644 --- a/src/seedsigner/views/seed_views.py +++ b/src/seedsigner/views/seed_views.py @@ -12,9 +12,9 @@ from seedsigner.controller import Controller from seedsigner.gui.components import FontAwesomeIconConstants, SeedSignerIconConstants from seedsigner.helpers import embit_utils -from seedsigner.gui.screens import (RET_CODE__BACK_BUTTON, ButtonListScreen, - WarningScreen, DireWarningScreen, seed_screens) -from seedsigner.gui.screens.screen import LargeIconStatusScreen, QRDisplayScreen +from seedsigner.gui.screens import seed_screens +from seedsigner.gui.screens.screen import (LargeIconStatusScreen, QRDisplayScreen, RET_CODE__BACK_BUTTON, ButtonListScreen, + WarningScreen, DireWarningScreen) from seedsigner.models.decode_qr import DecodeQR from seedsigner.models.encode_qr import CompactSeedQrEncoder, GenericStaticQrEncoder, SeedQrEncoder, SpecterXPubQrEncoder, StaticXpubQrEncoder, UrXpubQrEncoder from seedsigner.models.psbt_parser import PSBTParser diff --git a/src/seedsigner/views/settings_views.py b/src/seedsigner/views/settings_views.py index e2a742ca7..743c45c9b 100644 --- a/src/seedsigner/views/settings_views.py +++ b/src/seedsigner/views/settings_views.py @@ -4,7 +4,8 @@ from .view import View, Destination, MainMenuView -from seedsigner.gui.screens import (RET_CODE__BACK_BUTTON, ButtonListScreen, settings_screens) +from seedsigner.gui.screens import settings_screens +from seedsigner.gui.screens.screen import (RET_CODE__BACK_BUTTON, ButtonListScreen) from seedsigner.models.settings import Settings, SettingsConstants, SettingsDefinition logger = logging.getLogger(__name__) diff --git a/src/seedsigner/views/tools_views.py b/src/seedsigner/views/tools_views.py index 8ba7e92f2..e211dadd4 100644 --- a/src/seedsigner/views/tools_views.py +++ b/src/seedsigner/views/tools_views.py @@ -9,7 +9,7 @@ from seedsigner.controller import Controller from seedsigner.gui.components import FontAwesomeIconConstants, GUIConstants, SeedSignerIconConstants -from seedsigner.gui.screens import (RET_CODE__BACK_BUTTON, ButtonListScreen) +from seedsigner.gui.screens.screen import (RET_CODE__BACK_BUTTON, ButtonListScreen) from seedsigner.gui.screens.tools_screens import (ToolsCalcFinalWordDoneScreen, ToolsCalcFinalWordFinalizePromptScreen, ToolsCalcFinalWordScreen, ToolsCoinFlipEntryScreen, ToolsDiceEntropyEntryScreen, ToolsImageEntropyFinalImageScreen, ToolsImageEntropyLivePreviewScreen, ToolsAddressExplorerAddressTypeScreen) diff --git a/src/seedsigner/views/view.py b/src/seedsigner/views/view.py index a7c83d49d..d44ecf986 100644 --- a/src/seedsigner/views/view.py +++ b/src/seedsigner/views/view.py @@ -2,8 +2,8 @@ from typing import Type from seedsigner.gui.components import FontAwesomeIconConstants, SeedSignerIconConstants -from seedsigner.gui.screens import RET_CODE__POWER_BUTTON, RET_CODE__BACK_BUTTON -from seedsigner.gui.screens.screen import BaseScreen, DireWarningScreen, LargeButtonScreen, PowerOffScreen, PowerOffNotRequiredScreen, ResetScreen, WarningScreen +from seedsigner.gui.screens.screen import (RET_CODE__POWER_BUTTON, RET_CODE__BACK_BUTTON, + BaseScreen, DireWarningScreen, LargeButtonScreen, PowerOffScreen, PowerOffNotRequiredScreen, ResetScreen, WarningScreen) from seedsigner.models.settings import Settings, SettingsConstants from seedsigner.models.settings_definition import SettingsDefinition from seedsigner.models.threads import BaseThread diff --git a/tests/test_controller.py b/tests/test_controller.py index 375ae9ff3..b7db4ea72 100644 --- a/tests/test_controller.py +++ b/tests/test_controller.py @@ -22,7 +22,7 @@ def test_reset_controller(self): def test_singleton_init_fails(self): """ The Controller should not allow any code to instantiate it via Controller() """ with pytest.raises(Exception): - c = Controller() + _ = Controller() def test_handle_exception(reset_controller): diff --git a/tests/test_decodepsbtqr.py b/tests/test_decodepsbtqr.py index 9b7d6981d..3fd39842e 100644 --- a/tests/test_decodepsbtqr.py +++ b/tests/test_decodepsbtqr.py @@ -283,8 +283,8 @@ def test_short_4_letter_mnemonic_qr(): def test_bitcoin_address(): bad1 = "loremipsum" - bad2 = "0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae" - bad3 = "121802020768124106400009195602431595117715840445" + # bad2 = "0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae" + # bad3 = "121802020768124106400009195602431595117715840445" legacy_address1 = "1KFHE7w8BhaENAswwryaoccDb6qcT6DbYY" legacy_address2 = "16ftSEQ4ctQFDtVZiUBusQUjRrGhM3JYwe" @@ -296,7 +296,7 @@ def test_bitcoin_address(): test_nested_segwit_address = "2N6JbrvPMMwbBhu2KxqXyyHUQz3XKspvyfm" main_bech32_address2 = "bitcoin:bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq?amount=12000" - main_bech32_address3 = "BITCOIN:bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq?junk" + # main_bech32_address3 = "BITCOIN:bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq?junk" d = DecodeQR() d.add_data(bad1) diff --git a/tests/test_embit_utils.py b/tests/test_embit_utils.py index 52f37b755..3ca2abdf2 100644 --- a/tests/test_embit_utils.py +++ b/tests/test_embit_utils.py @@ -399,7 +399,7 @@ def test_parse_derivation_path(): (None, SC.CUSTOM_DERIVATION, False, 5): "m/123'/9083270/9083270/9083270/9083270/0/5", # non-standard change and/or index - (None, SC.CUSTOM_DERIVATION, None, 5): "m/9'/78/5", + # (None, SC.CUSTOM_DERIVATION, None, 5): "m/9'/78/5", (None, SC.CUSTOM_DERIVATION, None, 5): "m/9'/78'/5", (None, SC.CUSTOM_DERIVATION, None, None): "m/9'/78'/5'", (None, SC.CUSTOM_DERIVATION, False, None): "m/9'/0/5'", diff --git a/tests/test_flows.py b/tests/test_flows.py index acb8e8a32..1033c89e8 100644 --- a/tests/test_flows.py +++ b/tests/test_flows.py @@ -79,7 +79,7 @@ def test_FlowTestUnexpectedRedirectException(self): """ If the FlowStep doesn't specify is_redirect when the View redirects, raise FlowTestUnexpectedRedirectException """ - with pytest.raises(FlowTestUnexpectedRedirectException) as e: + with pytest.raises(FlowTestUnexpectedRedirectException): self.run_sequence([ FlowStep(SeedsMenuView, button_data_selection=SeedsMenuView.LOAD), # <-- No seeds loaded, so it'll redirect elsewhere ]) diff --git a/tests/test_flows_seed.py b/tests/test_flows_seed.py index f6ef501d4..024939a23 100644 --- a/tests/test_flows_seed.py +++ b/tests/test_flows_seed.py @@ -264,7 +264,7 @@ def test_export_xpub_disabled_not_available_flow(self): ) # test that taproot is not an option via exception raised when choice is taproot - with pytest.raises(FlowTestInvalidButtonDataSelectionException) as e: + with pytest.raises(FlowTestInvalidButtonDataSelectionException): self.run_sequence( initial_destination_view_args=dict(seed_num=0), sequence=[ @@ -275,7 +275,7 @@ def test_export_xpub_disabled_not_available_flow(self): ) # test that nunchuk is not an option via exception raised when choice is nunchuk - with pytest.raises(FlowTestInvalidButtonDataSelectionException) as e: + with pytest.raises(FlowTestInvalidButtonDataSelectionException): self.run_sequence( initial_destination_view_args=dict(seed_num=0), sequence=[ diff --git a/tests/test_psbt_parser.py b/tests/test_psbt_parser.py index 474d671b0..f011987c8 100644 --- a/tests/test_psbt_parser.py +++ b/tests/test_psbt_parser.py @@ -137,7 +137,7 @@ def test_p2sh_p2wpkh_nested_segwit(): """ - descriptor = Descriptor.from_string("sh(wpkh([c751dc07/49h/1h/0h]tpubDDS23bf7c9mdfWpuvA61HHCYDusq25UtMNYsFagKPNMNWHSm8bvwmNNP2KSpivN3gQWAK8fhDFk3dzgoBn9rPoMncKxJuqNAv7sJMShbZ6i/<0;1>/*))#7sn8gf37".replace("<0;1>", "{0,1}")) + # descriptor = Descriptor.from_string("sh(wpkh([c751dc07/49h/1h/0h]tpubDDS23bf7c9mdfWpuvA61HHCYDusq25UtMNYsFagKPNMNWHSm8bvwmNNP2KSpivN3gQWAK8fhDFk3dzgoBn9rPoMncKxJuqNAv7sJMShbZ6i/<0;1>/*))#7sn8gf37".replace("<0;1>", "{0,1}")) psbt_base64 = "cHNidP8BAH4CAAAAAXfY5crHl+bXtTvKvdo2MaFQeIXw+P+3kzZwBRgw84lFAQAAAAD9////AhjaAAAAAAAAF6kUSop8lEmO4FB1AyV1GJe2bygA7ASHSGsBAAAAAAAiACCHttDIHkeECumMJgZ2643Hhd8rXFnv0ZbDSYM8esN9UIouEwBPAQQ1h88Dv3UWAIAAAACfHgAYuw3ODwXCSP0valI9edAB1t3EInR2TXkbOd+F+AJgmJs8XUkZD5zQAgd3+/ijOqVphlWUMzxDnRorBQYEgxDHUdwHMQAAgAEAAIAAAACAAAEBIBFGAgAAAAAAF6kU7ijES3iWT8u0+44/blPlLfh9WkyHAQMEAQAAAAEEFgAUX7JspW1r0gC+WkUHwGABJ8DU9f8iBgO1/adRC+r8XJ/bjnfdwk3740n0m8gE3+xN8GHsNrxDUxjHUdwHMQAAgAEAAIAAAACAAQAAAAAAAAAAAQAWABT8V9vY29XR8niVYdVSF9H4zRTAbiICArH6DjPShnzXiaAnc2BR1f61QQliH0BOhqAvksByf3e9GMdR3AcxAACAAQAAgAAAAIABAAAAAQAAAAAA" raw = a2b_base64(psbt_base64) tx = psbt.PSBT.parse(raw) From 241e972cd4107d315dc97a96b4f0fe20135195cf Mon Sep 17 00:00:00 2001 From: Daniel Bast <2790401+dbast@users.noreply.github.com> Date: Mon, 29 Jul 2024 12:10:13 +0200 Subject: [PATCH 4/4] More fixes for screen short generator --- src/seedsigner/views/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/seedsigner/views/__init__.py b/src/seedsigner/views/__init__.py index 98ae81b58..2223ddd6c 100644 --- a/src/seedsigner/views/__init__.py +++ b/src/seedsigner/views/__init__.py @@ -1,3 +1,3 @@ -from .view import MainMenuView, BackStackView # base class has to be first +from .view import MainMenuView, BackStackView, NotYetImplementedView, PowerOptionsView, RestartView, UnhandledExceptionView # base class has to be first -__all__ = [MainMenuView, BackStackView] +__all__ = [MainMenuView, BackStackView, NotYetImplementedView, PowerOptionsView, RestartView, UnhandledExceptionView]