Avoid relative imports in test_utils scripts
What changed, and why it matters
This commit only changes how test helper scripts locate and import other test code. It makes the test utilities work regardless of which folder a script is run from. There is no change to the actual Ledger Bitcoin app, wallet logic, or anything end users interact with.
No security action required. Treat as a normal test-infrastructure maintenance commit.
Security signals we found
No security-relevant code changes
Only test utility import paths modified
No cryptographic, parsing, or transaction-handling logic altered
Evidence from the diff
The patch removes relative Python imports (e.g., from . import ...) inside the test_utils/ directory and instead adds the repository root to sys.path so scripts can use absolute imports such as from test_utils import ... and from bitcoin_client.ledger_bitcoin .... It also fixes one incorrect import path (ledger_bitcoin.embit.descriptor.miniscript → bitcoin_client.ledger_bitcoin.embit.descriptor.miniscript). All modified files are test/infrastructure code; no application source code is touched.
Changed components
test_utils/__init__.pytest_utils/fixtures.pytest_utils/musig2.pytest_utils/speculos.pytest_utils/txmaker.pytest_utils/wallet_policy.pyInspect captured patch +43 / −8
diff --git a/test_utils/__init__.py b/test_utils/__init__.py
index d0bb333..b25ed8a 100644
--- a/test_utils/__init__.py
+++ b/test_utils/__init__.py
@@ -1,8 +1,14 @@
import re
+import sys
+import os
import hashlib
from typing import Literal, Union
+_REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+if _REPO_ROOT not in sys.path:
+ sys.path.insert(0, _REPO_ROOT)
+
from mnemonic import Mnemonic
from bip32 import BIP32
diff --git a/test_utils/fixtures.py b/test_utils/fixtures.py
index 8879aa5..f286f05 100644
--- a/test_utils/fixtures.py
+++ b/test_utils/fixtures.py
@@ -3,10 +3,15 @@ import pytest
from pathlib import Path
import re
import os
+import sys
import json
from typing import Literal, Union
-from . import default_settings, SpeculosGlobals
+_REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+if _REPO_ROOT not in sys.path:
+ sys.path.insert(0, _REPO_ROOT)
+
+from test_utils import default_settings, SpeculosGlobals
from bitcoin_client.ledger_bitcoin import TransportClient, Client, Chain, createClient
diff --git a/test_utils/musig2.py b/test_utils/musig2.py
index 0de2295..bb0a001 100644
--- a/test_utils/musig2.py
+++ b/test_utils/musig2.py
@@ -28,12 +28,18 @@ import struct
from typing import Dict, Iterable, Iterator, List, Optional, Set, Tuple, Union
from abc import ABC, abstractmethod
+import sys
+import os
+
+_REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+if _REPO_ROOT not in sys.path:
+ sys.path.insert(0, _REPO_ROOT)
+
import base58
from test_utils.taproot_sighash import SIGHASH_DEFAULT, TaprootSignatureHash
-
-from . import bip0327, bip0340, hash160, sha256
-from . import taproot
+from test_utils import bip0327, bip0340, hash160, sha256
+from test_utils import taproot
from bitcoin_client.ledger_bitcoin.embit.descriptor.miniscript import Miniscript
from bitcoin_client.ledger_bitcoin.psbt import PSBT, PartiallySignedInput
diff --git a/test_utils/speculos.py b/test_utils/speculos.py
index 2a321c9..50b79de 100644
--- a/test_utils/speculos.py
+++ b/test_utils/speculos.py
@@ -1,7 +1,13 @@
from contextlib import contextmanager
import json
+import sys
+import os
from typing import Union
+_REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+if _REPO_ROOT not in sys.path:
+ sys.path.insert(0, _REPO_ROOT)
+
from bitcoin_client.ledger_bitcoin.client_base import TransportClient
from speculos.client import SpeculosClient
diff --git a/test_utils/txmaker.py b/test_utils/txmaker.py
index 279ac4e..04fb07d 100644
--- a/test_utils/txmaker.py
+++ b/test_utils/txmaker.py
@@ -5,11 +5,18 @@
# Ledger bitcoin app might not be filled in.
+import sys
+import os
from io import BytesIO
from random import randint
import re
from typing import List, Tuple, Optional, Union
+
+_REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+if _REPO_ROOT not in sys.path:
+ sys.path.insert(0, _REPO_ROOT)
+
from bitcoin_client.ledger_bitcoin import WalletPolicy, WalletType
from bitcoin_client.ledger_bitcoin.key import ExtendedKey, KeyOriginInfo, parse_path, get_taproot_output_key
from bitcoin_client.ledger_bitcoin.psbt import PSBT, PartiallySignedInput, PartiallySignedOutput
@@ -22,7 +29,7 @@ from embit.bip39 import mnemonic_to_seed
from hashlib import sha256
-from ledger_bitcoin.embit.descriptor.miniscript import Miniscript
+from bitcoin_client.ledger_bitcoin.embit.descriptor.miniscript import Miniscript
from test_utils import bip0340
from test_utils.wallet_policy import DescriptorTemplate, KeyPlaceholder, PlainKeyPlaceholder, TrDescriptorTemplate, WshDescriptorTemplate, derive_plain_descriptor, tapleaf_hash
diff --git a/test_utils/wallet_policy.py b/test_utils/wallet_policy.py
index 07413fa..3830f99 100644
--- a/test_utils/wallet_policy.py
+++ b/test_utils/wallet_policy.py
@@ -3,16 +3,21 @@
# possible types of descriptor templates from the BIP.
# Only to be used for testing purposes.
+import sys
+import os
from abc import ABC, abstractmethod
from dataclasses import dataclass
from io import BytesIO
import re
from typing import Iterator, List, Optional, Tuple, Type, Union
-from ledger_bitcoin.embit.descriptor.miniscript import Miniscript
-from ledger_bitcoin.key import ExtendedKey
+_REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+if _REPO_ROOT not in sys.path:
+ sys.path.insert(0, _REPO_ROOT)
-from .taproot import ser_script, tagged_hash
+from bitcoin_client.ledger_bitcoin.embit.descriptor.miniscript import Miniscript
+from bitcoin_client.ledger_bitcoin.key import ExtendedKey
+from test_utils.taproot import ser_script, tagged_hash
def tapleaf_hash(script: Optional[bytes], leaf_version=b'\xC0') -> Optional[bytes]:
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.