Skip to content

Conversation

@codeflash-ai
Copy link

@codeflash-ai codeflash-ai bot commented Oct 31, 2025

📄 21% (0.21x) speedup for HardwareHandlerBase.get_wallet in electrum/hw_wallet/plugin.py

⏱️ Runtime : 387 microseconds 319 microseconds (best of 182 runs)

📝 Explanation and details

The optimization achieves a 21% speedup through two key changes:

  1. Local variable caching: win = self.win stores the attribute in a local variable. Python's local variable lookup (LOAD_FAST) is faster than attribute access (LOAD_ATTR) because it uses array indexing instead of dictionary lookups.

  2. Single operation replacement: Replaces the two-step hasattr(self.win, 'wallet') + self.win.wallet pattern with a single getattr(win, 'wallet', None) call. This eliminates duplicate attribute lookups since hasattr internally performs the same attribute resolution as the subsequent access.

The line profiler shows the optimization reduces both the number of attribute accesses (from 3 total self.win lookups to 1) and overall execution time. The performance gains are most significant in scenarios with frequent method calls - test cases show 14-30% improvements when objects have the wallet attribute, and the large-scale tests demonstrate 23-24% speedups with repeated calls.

The optimization is particularly effective for the common case where win exists and has a wallet attribute, as seen in the annotated tests where most positive cases show 12-30% improvements.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 2657 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
🌀 Generated Regression Tests and Runtime
import pytest
from electrum.hw_wallet.plugin import HardwareHandlerBase


# function to test
class Abstract_Wallet:
    """Stub for Abstract_Wallet base class."""
    def __init__(self, name):
        self.name = name

class DummyWinWithWallet:
    """Dummy window object with a 'wallet' attribute."""
    def __init__(self, wallet):
        self.wallet = wallet

class DummyWinNoWallet:
    """Dummy window object without a 'wallet' attribute."""
    pass
from electrum.hw_wallet.plugin import HardwareHandlerBase

# unit tests

# --------------------
# Basic Test Cases
# --------------------

def test_get_wallet_with_valid_wallet():
    """Basic: win is set and has a wallet attribute, should return the wallet."""
    handler = HardwareHandlerBase()
    wallet = Abstract_Wallet("alice")
    handler.win = DummyWinWithWallet(wallet)
    codeflash_output = handler.get_wallet(); result = codeflash_output # 749ns -> 655ns (14.4% faster)

def test_get_wallet_with_different_wallet_objects():
    """Basic: win.wallet can be any object, not just Abstract_Wallet."""
    handler = HardwareHandlerBase()
    dummy_obj = object()
    handler.win = DummyWinWithWallet(dummy_obj)
    codeflash_output = handler.get_wallet(); result = codeflash_output # 657ns -> 557ns (18.0% faster)

def test_get_wallet_with_none_wallet():
    """Basic: win.wallet can be None."""
    handler = HardwareHandlerBase()
    handler.win = DummyWinWithWallet(None)
    codeflash_output = handler.get_wallet(); result = codeflash_output # 570ns -> 539ns (5.75% faster)

# --------------------
# Edge Test Cases
# --------------------

def test_get_wallet_win_is_none():
    """Edge: win is None, should return None."""
    handler = HardwareHandlerBase()
    handler.win = None
    codeflash_output = handler.get_wallet(); result = codeflash_output # 384ns -> 420ns (8.57% slower)

def test_get_wallet_win_without_wallet_attribute():
    """Edge: win exists but has no 'wallet' attribute, should return None."""
    handler = HardwareHandlerBase()
    handler.win = DummyWinNoWallet()
    codeflash_output = handler.get_wallet(); result = codeflash_output # 590ns -> 575ns (2.61% faster)

def test_get_wallet_win_is_falsey_but_not_none():
    """Edge: win is a falsey value (like 0 or ''), but not None. Should not return wallet."""
    handler = HardwareHandlerBase()
    handler.win = 0  # int, no 'wallet' attribute
    codeflash_output = handler.get_wallet(); result = codeflash_output # 510ns -> 511ns (0.196% slower)
    handler.win = ""  # str, no 'wallet' attribute
    codeflash_output = handler.get_wallet(); result = codeflash_output # 223ns -> 223ns (0.000% faster)

def test_get_wallet_win_is_object_with_wallet_property():
    """Edge: win has a 'wallet' property (not attribute), should return its value."""
    class WinWithWalletProperty:
        @property
        def wallet(self):
            return "property_wallet"
    handler = HardwareHandlerBase()
    handler.win = WinWithWalletProperty()
    codeflash_output = handler.get_wallet(); result = codeflash_output # 808ns -> 703ns (14.9% faster)

def test_get_wallet_win_is_object_with_wallet_method():
    """Edge: win has a 'wallet' method, should return the method (not call it)."""
    class WinWithWalletMethod:
        def wallet(self):
            return "method_wallet"
    handler = HardwareHandlerBase()
    handler.win = WinWithWalletMethod()
    codeflash_output = handler.get_wallet(); result = codeflash_output # 728ns -> 619ns (17.6% faster)

def test_get_wallet_win_is_object_with_wallet_set_to_false():
    """Edge: win.wallet is a falsey value (e.g., False, 0, empty string). Should return that value."""
    handler = HardwareHandlerBase()
    for val in (False, 0, "", [], {}):
        handler.win = DummyWinWithWallet(val)
        codeflash_output = handler.get_wallet(); result = codeflash_output # 1.53μs -> 1.33μs (14.5% faster)

def test_get_wallet_win_is_object_with_wallet_attribute_but_raises():
    """Edge: win.wallet attribute raises exception when accessed."""
    class WinWithRaisingWallet:
        @property
        def wallet(self):
            raise RuntimeError("Access denied")
    handler = HardwareHandlerBase()
    handler.win = WinWithRaisingWallet()
    with pytest.raises(RuntimeError):
        codeflash_output = handler.get_wallet(); _ = codeflash_output # 1.29μs -> 1.38μs (6.53% slower)

def test_get_wallet_win_is_object_with_wallet_set_to_self():
    """Edge: win.wallet is a reference to win itself."""
    handler = HardwareHandlerBase()
    win = DummyWinWithWallet(None)
    win.wallet = win
    handler.win = win
    codeflash_output = handler.get_wallet(); result = codeflash_output # 579ns -> 519ns (11.6% faster)

# --------------------
# Large Scale Test Cases
# --------------------

def test_get_wallet_many_handler_instances():
    """Large scale: Create many handler instances and verify correct wallet retrieval."""
    N = 500  # keep under 1000 for performance
    wallets = [Abstract_Wallet(f"user_{i}") for i in range(N)]
    handlers = [HardwareHandlerBase() for _ in range(N)]
    for i in range(N):
        handlers[i].win = DummyWinWithWallet(wallets[i])
    for i in range(N):
        codeflash_output = handlers[i].get_wallet() # 106μs -> 85.7μs (24.3% faster)

def test_get_wallet_many_handler_instances_with_none_and_missing_wallet():
    """Large scale: Mix of valid wallets, None, and missing wallet attributes."""
    N = 300
    wallets = [Abstract_Wallet(f"user_{i}") for i in range(N)]
    handlers = []
    # 1/3 with valid wallet, 1/3 with win=None, 1/3 with win but no wallet
    for i in range(N):
        h = HardwareHandlerBase()
        if i % 3 == 0:
            h.win = DummyWinWithWallet(wallets[i])
        elif i % 3 == 1:
            h.win = None
        else:
            h.win = DummyWinNoWallet()
        handlers.append(h)
    for i in range(N):
        if i % 3 == 0:
            codeflash_output = handlers[i].get_wallet()
        else:
            codeflash_output = handlers[i].get_wallet()

def test_get_wallet_performance_large_scale():
    """Large scale: Ensure performance does not degrade with many calls."""
    handler = HardwareHandlerBase()
    wallet = Abstract_Wallet("perf")
    handler.win = DummyWinWithWallet(wallet)
    for _ in range(1000):
        codeflash_output = handler.get_wallet() # 201μs -> 162μs (23.8% faster)

# --------------------
# Miscellaneous/Negative Test Cases
# --------------------

def test_get_wallet_win_is_unusual_object():
    """Edge: win is an object with __getattr__ that returns a wallet for any attribute."""
    class WinWithDynamicWallet:
        def __getattr__(self, name):
            if name == "wallet":
                return "dynamic_wallet"
            raise AttributeError(name)
    handler = HardwareHandlerBase()
    handler.win = WinWithDynamicWallet()
    codeflash_output = handler.get_wallet(); result = codeflash_output # 2.04μs -> 1.66μs (23.1% faster)

def test_get_wallet_win_is_object_with_wallet_is_exception():
    """Edge: win.wallet is set to an exception object."""
    handler = HardwareHandlerBase()
    exc = Exception("wallet is exception")
    handler.win = DummyWinWithWallet(exc)
    codeflash_output = handler.get_wallet(); result = codeflash_output # 491ns -> 409ns (20.0% faster)

def test_get_wallet_win_is_object_with_wallet_is_callable():
    """Edge: win.wallet is a callable object."""
    handler = HardwareHandlerBase()
    def wallet_func():
        return "called"
    handler.win = DummyWinWithWallet(wallet_func)
    codeflash_output = handler.get_wallet(); result = codeflash_output # 425ns -> 417ns (1.92% faster)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
#------------------------------------------------
from typing import Optional

# imports
import pytest  # used for our unit tests
from electrum.hw_wallet.plugin import HardwareHandlerBase

# ------------------- UNIT TESTS -------------------

# 1. BASIC TEST CASES


def test_get_wallet_returns_none_when_win_is_none():
    # Test: win is None
    handler = HardwareHandlerBase()
    handler.win = None
    codeflash_output = handler.get_wallet(); result = codeflash_output # 507ns -> 522ns (2.87% slower)

def test_get_wallet_returns_none_when_win_has_no_wallet():
    # Test: win is set, but has no wallet attribute
    handler = HardwareHandlerBase()
    class Win:
        pass
    handler.win = Win()
    codeflash_output = handler.get_wallet(); result = codeflash_output # 625ns -> 666ns (6.16% slower)

def test_get_wallet_returns_wallet_when_wallet_is_none():
    # Test: win.wallet is None (should return None, but not error)
    handler = HardwareHandlerBase()
    class Win:
        wallet = None
    handler.win = Win()
    codeflash_output = handler.get_wallet(); result = codeflash_output # 704ns -> 591ns (19.1% faster)

# 2. EDGE TEST CASES

def test_get_wallet_with_win_wallet_set_to_non_wallet_object():
    # Test: win.wallet is set to a non-wallet object
    handler = HardwareHandlerBase()
    class Win:
        wallet = "not_a_wallet"
    handler.win = Win()
    codeflash_output = handler.get_wallet(); result = codeflash_output # 635ns -> 567ns (12.0% faster)

def test_get_wallet_with_win_as_non_object():
    # Test: win is set to a non-object (e.g., int, str)
    handler = HardwareHandlerBase()
    handler.win = 42
    codeflash_output = handler.get_wallet(); result = codeflash_output # 502ns -> 507ns (0.986% slower)

    handler.win = "hello"
    codeflash_output = handler.get_wallet(); result = codeflash_output # 223ns -> 237ns (5.91% slower)

def test_get_wallet_with_win_wallet_property():
    # Test: win.wallet is a property, not an attribute
    handler = HardwareHandlerBase()
    class Win:
        @property
        def wallet(self):
            return Abstract_Wallet(balance=999)
    handler.win = Win()
    codeflash_output = handler.get_wallet(); result = codeflash_output

def test_get_wallet_with_win_wallet_set_to_falsey_value():
    # Test: win.wallet is set to a falsey value (0, False, empty string)
    handler = HardwareHandlerBase()
    class Win:
        wallet = 0
    handler.win = Win()
    codeflash_output = handler.get_wallet(); result = codeflash_output # 863ns -> 737ns (17.1% faster)

    class Win2:
        wallet = ""
    handler.win = Win2()
    codeflash_output = handler.get_wallet(); result = codeflash_output # 370ns -> 298ns (24.2% faster)

    class Win3:
        wallet = False
    handler.win = Win3()
    codeflash_output = handler.get_wallet(); result = codeflash_output # 253ns -> 225ns (12.4% faster)

def test_get_wallet_with_win_wallet_set_to_list():
    # Test: win.wallet is set to a list
    handler = HardwareHandlerBase()
    class Win:
        wallet = [1,2,3]
    handler.win = Win()
    codeflash_output = handler.get_wallet(); result = codeflash_output # 702ns -> 539ns (30.2% faster)


def test_get_wallet_with_win_wallet_set_to_callable():
    # Test: win.wallet is a function
    handler = HardwareHandlerBase()
    class Win:
        @staticmethod
        def wallet():
            return Abstract_Wallet(balance=555)
    handler.win = Win()
    codeflash_output = handler.get_wallet(); result = codeflash_output # 933ns -> 740ns (26.1% faster)

# 3. LARGE SCALE TEST CASES




def test_get_wallet_with_large_win_list():
    # Test: handler.win is a list of objects, none of which have wallet attribute
    handler = HardwareHandlerBase()
    handler.win = [object() for _ in range(500)]
    codeflash_output = handler.get_wallet(); result = codeflash_output # 655ns -> 630ns (3.97% faster)

To edit these changes git checkout codeflash/optimize-HardwareHandlerBase.get_wallet-mhf87uhy and push.

Codeflash Static Badge

The optimization achieves a **21% speedup** through two key changes:

1. **Local variable caching**: `win = self.win` stores the attribute in a local variable. Python's local variable lookup (LOAD_FAST) is faster than attribute access (LOAD_ATTR) because it uses array indexing instead of dictionary lookups.

2. **Single operation replacement**: Replaces the two-step `hasattr(self.win, 'wallet')` + `self.win.wallet` pattern with a single `getattr(win, 'wallet', None)` call. This eliminates duplicate attribute lookups since `hasattr` internally performs the same attribute resolution as the subsequent access.

The line profiler shows the optimization reduces both the number of attribute accesses (from 3 total `self.win` lookups to 1) and overall execution time. The performance gains are most significant in scenarios with frequent method calls - test cases show 14-30% improvements when objects have the `wallet` attribute, and the large-scale tests demonstrate 23-24% speedups with repeated calls.

The optimization is particularly effective for the common case where `win` exists and has a `wallet` attribute, as seen in the annotated tests where most positive cases show 12-30% improvements.
@codeflash-ai codeflash-ai bot requested a review from mashraf-222 October 31, 2025 19:08
@codeflash-ai codeflash-ai bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash labels Oct 31, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant