Skip to content

Conversation

@codeflash-ai
Copy link

@codeflash-ai codeflash-ai bot commented Nov 13, 2025

📄 31% (0.31x) speedup for lbank.parse_transaction_status in python/ccxt/async_support/lbank.py

⏱️ Runtime : 7.95 milliseconds 6.09 milliseconds (best of 12 runs)

📝 Explanation and details

The optimization achieves a 30% speedup by eliminating redundant dictionary construction in the parse_transaction_status method.

What was optimized:
The original code recreated the same statuses dictionary on every method call - a static mapping that never changes. With 8,050 calls in the profiler, this meant creating 8,050 identical dictionaries containing the same status mappings for 'deposit' and 'withdrawal' transactions.

Key change:
Moved the statuses dictionary outside the method as a module-level constant LBANK_TRANSACTION_STATUSES. The method now references this pre-built structure instead of reconstructing it each time.

Why this leads to speedup:

  • Eliminates object construction overhead: Python dictionary creation involves memory allocation, key-value insertion, and hash table setup - all avoided now
  • Reduces memory pressure: No repeated allocation/deallocation of identical dictionaries
  • Better cache locality: Single static dictionary stays in memory rather than being recreated

Performance characteristics:
From the line profiler, the original version spent ~74.5% of execution time just on the return statement (which included dictionary construction). The optimized version shows the entire method execution time reduced from 69.9ms to 50.7ms total, with consistent 20-42% improvements across all test cases.

Impact assessment:
This optimization is particularly beneficial for high-frequency transaction status parsing scenarios, as evidenced by the consistent performance gains across various edge cases and batch operations in the test suite. The method maintains identical functionality while eliminating wasteful repeated work.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 8097 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
🌀 Generated Regression Tests and Runtime
import pytest
from ccxt.async_support.lbank import lbank


# Create a fixture for the lbank instance
@pytest.fixture
def lbank_instance():
    return lbank()

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

def test_deposit_pending(lbank_instance):
    # Deposit status '1' should map to 'pending'
    codeflash_output = lbank_instance.parse_transaction_status('1', 'deposit') # 3.67μs -> 2.76μs (32.7% faster)

def test_deposit_ok(lbank_instance):
    # Deposit status '2' should map to 'ok'
    codeflash_output = lbank_instance.parse_transaction_status('2', 'deposit') # 3.72μs -> 2.84μs (30.9% faster)

def test_deposit_failed(lbank_instance):
    # Deposit status '3' should map to 'failed'
    codeflash_output = lbank_instance.parse_transaction_status('3', 'deposit') # 3.61μs -> 2.79μs (29.8% faster)

def test_deposit_canceled(lbank_instance):
    # Deposit status '4' should map to 'canceled'
    codeflash_output = lbank_instance.parse_transaction_status('4', 'deposit') # 3.45μs -> 2.81μs (22.7% faster)

def test_deposit_transfer(lbank_instance):
    # Deposit status '5' should map to 'transfer'
    codeflash_output = lbank_instance.parse_transaction_status('5', 'deposit') # 3.53μs -> 2.77μs (27.6% faster)

def test_withdrawal_pending(lbank_instance):
    # Withdrawal status '1' should map to 'pending'
    codeflash_output = lbank_instance.parse_transaction_status('1', 'withdrawal') # 3.53μs -> 2.94μs (20.0% faster)

def test_withdrawal_canceled(lbank_instance):
    # Withdrawal status '2' should map to 'canceled'
    codeflash_output = lbank_instance.parse_transaction_status('2', 'withdrawal') # 3.55μs -> 2.83μs (25.2% faster)

def test_withdrawal_failed(lbank_instance):
    # Withdrawal status '3' should map to 'failed'
    codeflash_output = lbank_instance.parse_transaction_status('3', 'withdrawal') # 3.61μs -> 2.78μs (29.8% faster)

def test_withdrawal_ok(lbank_instance):
    # Withdrawal status '4' should map to 'ok'
    codeflash_output = lbank_instance.parse_transaction_status('4', 'withdrawal') # 3.48μs -> 2.73μs (27.2% faster)

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

def test_invalid_status_deposit(lbank_instance):
    # Status not in mapping should return the input status
    codeflash_output = lbank_instance.parse_transaction_status('999', 'deposit') # 3.70μs -> 2.95μs (25.3% faster)

def test_invalid_status_withdrawal(lbank_instance):
    # Status not in mapping should return the input status
    codeflash_output = lbank_instance.parse_transaction_status('999', 'withdrawal') # 3.76μs -> 2.83μs (33.1% faster)

def test_invalid_type(lbank_instance):
    # Type not in mapping should return the input status
    codeflash_output = lbank_instance.parse_transaction_status('1', 'unknown') # 3.74μs -> 2.72μs (37.4% faster)

def test_none_status(lbank_instance):
    # None status should return None
    codeflash_output = lbank_instance.parse_transaction_status(None, 'deposit') # 3.82μs -> 3.00μs (27.4% faster)

def test_none_type(lbank_instance):
    # None type should return the input status
    codeflash_output = lbank_instance.parse_transaction_status('1', None) # 3.76μs -> 2.73μs (37.7% faster)

def test_empty_status(lbank_instance):
    # Empty string status should return empty string
    codeflash_output = lbank_instance.parse_transaction_status('', 'deposit') # 3.76μs -> 2.97μs (26.4% faster)

def test_empty_type(lbank_instance):
    # Empty string type should return the input status
    codeflash_output = lbank_instance.parse_transaction_status('1', '') # 3.56μs -> 2.80μs (27.1% faster)

def test_status_as_int(lbank_instance):
    # Status as integer should be converted to string and matched
    codeflash_output = lbank_instance.parse_transaction_status(1, 'deposit') # 3.84μs -> 3.10μs (24.0% faster)
    codeflash_output = lbank_instance.parse_transaction_status(2, 'withdrawal') # 1.51μs -> 1.06μs (42.9% faster)

def test_status_as_float_string(lbank_instance):
    # Status as float string should not match, returns input
    codeflash_output = lbank_instance.parse_transaction_status('1.0', 'deposit') # 3.88μs -> 2.89μs (34.2% faster)

def test_type_case_sensitivity(lbank_instance):
    # Type is case-sensitive, so 'Deposit' should not match
    codeflash_output = lbank_instance.parse_transaction_status('1', 'Deposit') # 3.77μs -> 2.70μs (39.6% faster)

def test_type_as_int(lbank_instance):
    # Type as integer should not match, returns input status
    codeflash_output = lbank_instance.parse_transaction_status('1', 123) # 3.83μs -> 2.81μs (36.0% faster)

def test_status_as_bool(lbank_instance):
    # Status as boolean should be converted to string and not match, returns input
    codeflash_output = lbank_instance.parse_transaction_status(True, 'deposit') # 3.79μs -> 2.95μs (28.6% faster)
    codeflash_output = lbank_instance.parse_transaction_status(False, 'withdrawal') # 1.42μs -> 1.13μs (26.1% faster)

def test_type_as_bool(lbank_instance):
    # Type as boolean should not match, returns input status
    codeflash_output = lbank_instance.parse_transaction_status('1', True) # 3.83μs -> 2.85μs (34.3% faster)

def test_status_as_none_type_as_none(lbank_instance):
    # Both status and type None should return None
    codeflash_output = lbank_instance.parse_transaction_status(None, None) # 3.80μs -> 2.86μs (32.9% faster)





def test_large_number_of_statuses_deposit(lbank_instance):
    # Test with 1000 random status codes, only '1'-'5' should map, rest should return input
    for i in range(1, 1001):
        status = str(i)
        if status in {'1', '2', '3', '4', '5'}:
            expected = {
                '1': 'pending',
                '2': 'ok',
                '3': 'failed',
                '4': 'canceled',
                '5': 'transfer',
            }[status]
        else:
            expected = status
        codeflash_output = lbank_instance.parse_transaction_status(status, 'deposit') # 963μs -> 735μs (31.0% faster)

def test_large_number_of_statuses_withdrawal(lbank_instance):
    # Test with 1000 random status codes, only '1'-'4' should map, rest should return input
    for i in range(1, 1001):
        status = str(i)
        if status in {'1', '2', '3', '4'}:
            expected = {
                '1': 'pending',
                '2': 'canceled',
                '3': 'failed',
                '4': 'ok',
            }[status]
        else:
            expected = status
        codeflash_output = lbank_instance.parse_transaction_status(status, 'withdrawal') # 967μs -> 736μs (31.4% faster)

def test_large_number_of_types(lbank_instance):
    # Test with 1000 types, only 'deposit' and 'withdrawal' should map, rest should return input status
    for i in range(1000):
        type_str = f'type_{i}'
        codeflash_output = lbank_instance.parse_transaction_status('1', type_str) # 1.02ms -> 786μs (29.2% faster)
        codeflash_output = lbank_instance.parse_transaction_status('999', type_str)

def test_performance_large_batch(lbank_instance):
    # Simulate a batch of 1000 calls for performance
    statuses_deposit = [str(i % 6) for i in range(1000)]  # Will cycle through 0-5
    types = ['deposit'] * 1000
    results = [lbank_instance.parse_transaction_status(s, t) for s, t in zip(statuses_deposit, types)]
    expected = []
    for s in statuses_deposit:
        if s in {'1', '2', '3', '4', '5'}:
            expected.append({
                '1': 'pending',
                '2': 'ok',
                '3': 'failed',
                '4': 'canceled',
                '5': 'transfer',
            }[s])
        else:
            expected.append(s)

def test_performance_large_batch_withdrawal(lbank_instance):
    # Simulate a batch of 1000 calls for withdrawal
    statuses_withdrawal = [str(i % 5) for i in range(1000)]  # Will cycle through 0-4
    types = ['withdrawal'] * 1000
    results = [lbank_instance.parse_transaction_status(s, t) for s, t in zip(statuses_withdrawal, types)]
    expected = []
    for s in statuses_withdrawal:
        if s in {'1', '2', '3', '4'}:
            expected.append({
                '1': 'pending',
                '2': 'canceled',
                '3': 'failed',
                '4': 'ok',
            }[s])
        else:
            expected.append(s)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
import pytest
from ccxt.async_support.lbank import lbank

# Create an instance for testing
lbank_instance = lbank()

# --------------------------
# 1. Basic Test Cases
# --------------------------

@pytest.mark.parametrize("status,type,expected", [
    # Deposit statuses
    ('1', 'deposit', 'pending'),    # deposit pending
    ('2', 'deposit', 'ok'),         # deposit ok
    ('3', 'deposit', 'failed'),     # deposit failed
    ('4', 'deposit', 'canceled'),   # deposit canceled
    ('5', 'deposit', 'transfer'),   # deposit transfer

    # Withdrawal statuses
    ('1', 'withdrawal', 'pending'),   # withdrawal pending
    ('2', 'withdrawal', 'canceled'),  # withdrawal canceled
    ('3', 'withdrawal', 'failed'),    # withdrawal failed
    ('4', 'withdrawal', 'ok'),        # withdrawal ok
])
def test_basic_known_statuses(status, type, expected):
    # Test known status mappings for both deposit and withdrawal
    codeflash_output = lbank_instance.parse_transaction_status(status, type); result = codeflash_output # 29.7μs -> 23.8μs (24.8% faster)

# --------------------------
# 2. Edge Test Cases
# --------------------------

def test_unknown_status_for_deposit():
    # Status not in deposit mapping should return status as-is
    unknown_status = '99'
    codeflash_output = lbank_instance.parse_transaction_status(unknown_status, 'deposit'); result = codeflash_output # 3.20μs -> 2.61μs (22.7% faster)

def test_unknown_status_for_withdrawal():
    # Status not in withdrawal mapping should return status as-is
    unknown_status = '99'
    codeflash_output = lbank_instance.parse_transaction_status(unknown_status, 'withdrawal'); result = codeflash_output # 3.18μs -> 2.39μs (33.1% faster)

def test_unknown_type():
    # Unknown type should return status as-is
    codeflash_output = lbank_instance.parse_transaction_status('1', 'foobar'); result = codeflash_output # 3.02μs -> 2.44μs (23.7% faster)

def test_unknown_type_and_status():
    # Unknown type and unknown status should return status as-is
    codeflash_output = lbank_instance.parse_transaction_status('999', 'foobar'); result = codeflash_output # 2.91μs -> 2.29μs (27.3% faster)

def test_none_status():
    # None as status should return None
    codeflash_output = lbank_instance.parse_transaction_status(None, 'deposit'); result = codeflash_output # 3.05μs -> 2.50μs (22.0% faster)

def test_none_type():
    # None as type should return status as-is
    codeflash_output = lbank_instance.parse_transaction_status('1', None); result = codeflash_output # 2.73μs -> 2.29μs (19.2% faster)

def test_none_status_and_type():
    # Both None should return None
    codeflash_output = lbank_instance.parse_transaction_status(None, None); result = codeflash_output # 3.04μs -> 2.15μs (41.4% faster)

def test_empty_string_status():
    # Empty string status should return empty string
    codeflash_output = lbank_instance.parse_transaction_status('', 'deposit'); result = codeflash_output # 2.98μs -> 2.44μs (22.1% faster)

def test_empty_string_type():
    # Empty string type should return status as-is
    codeflash_output = lbank_instance.parse_transaction_status('1', ''); result = codeflash_output # 2.84μs -> 2.14μs (32.4% faster)

def test_empty_string_status_and_type():
    # Both empty string should return empty string
    codeflash_output = lbank_instance.parse_transaction_status('', ''); result = codeflash_output # 2.76μs -> 2.30μs (19.8% faster)

def test_numeric_status():
    # Numeric status (int) should be converted to string and not found, so return as-is
    codeflash_output = lbank_instance.parse_transaction_status(1, 'deposit'); result = codeflash_output # 3.11μs -> 2.43μs (28.0% faster)

def test_case_sensitivity_of_type():
    # Type is case-sensitive, so 'Deposit' should not match 'deposit'
    codeflash_output = lbank_instance.parse_transaction_status('1', 'Deposit'); result = codeflash_output # 2.77μs -> 2.32μs (19.1% faster)


def test_type_as_unexpected_type():
    # Type as a non-string (e.g., int) should not match, so return status as-is
    codeflash_output = lbank_instance.parse_transaction_status('1', 123); result = codeflash_output # 4.68μs -> 3.82μs (22.7% faster)

# --------------------------
# 3. Large Scale Test Cases
# --------------------------

def test_large_batch_of_deposit_statuses():
    # Test a large batch of deposit statuses, including valid and invalid
    statuses = ['1', '2', '3', '4', '5', '99', '', None]
    expected = ['pending', 'ok', 'failed', 'canceled', 'transfer', '99', '', None]
    for i in range(100):  # 100 batches
        for status, exp in zip(statuses, expected):
            codeflash_output = lbank_instance.parse_transaction_status(status, 'deposit'); result = codeflash_output

def test_large_batch_of_withdrawal_statuses():
    # Test a large batch of withdrawal statuses, including valid and invalid
    statuses = ['1', '2', '3', '4', '99', '', None]
    expected = ['pending', 'canceled', 'failed', 'ok', '99', '', None]
    for i in range(100):  # 100 batches
        for status, exp in zip(statuses, expected):
            codeflash_output = lbank_instance.parse_transaction_status(status, 'withdrawal'); result = codeflash_output

def test_large_batch_of_unknown_types():
    # Test a large batch of unknown types, should always return status as-is
    statuses = ['1', '2', 'foo', '', None]
    for i in range(100):  # 100 batches
        for status in statuses:
            codeflash_output = lbank_instance.parse_transaction_status(status, 'unknown_type'); result = codeflash_output
            if status is None:
                pass
            else:
                pass

def test_performance_large_unique_statuses():
    # Test performance with 999 unique status values for deposit
    # Only '1'-'5' will map, rest will return themselves
    for i in range(1, 1000):
        status = str(i)
        codeflash_output = lbank_instance.parse_transaction_status(status, 'deposit'); result = codeflash_output # 956μs -> 735μs (30.0% faster)
        if status in ['1', '2', '3', '4', '5']:
            expected = {'1': 'pending', '2': 'ok', '3': 'failed', '4': 'canceled', '5': 'transfer'}[status]
        else:
            pass

def test_performance_large_unique_types():
    # Test performance with 999 unique types, all unknown, should return status as-is
    for i in range(1, 1000):
        type_ = f"randomtype{i}"
        codeflash_output = lbank_instance.parse_transaction_status('1', type_); result = codeflash_output # 1.00ms -> 775μs (29.6% faster)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

To edit these changes git checkout codeflash/optimize-lbank.parse_transaction_status-mhxnmgqv and push.

Codeflash Static Badge

The optimization achieves a **30% speedup** by eliminating redundant dictionary construction in the `parse_transaction_status` method.

**What was optimized:**
The original code recreated the same `statuses` dictionary on every method call - a static mapping that never changes. With 8,050 calls in the profiler, this meant creating 8,050 identical dictionaries containing the same status mappings for 'deposit' and 'withdrawal' transactions.

**Key change:**
Moved the `statuses` dictionary outside the method as a module-level constant `LBANK_TRANSACTION_STATUSES`. The method now references this pre-built structure instead of reconstructing it each time.

**Why this leads to speedup:**
- **Eliminates object construction overhead:** Python dictionary creation involves memory allocation, key-value insertion, and hash table setup - all avoided now
- **Reduces memory pressure:** No repeated allocation/deallocation of identical dictionaries
- **Better cache locality:** Single static dictionary stays in memory rather than being recreated

**Performance characteristics:**
From the line profiler, the original version spent ~74.5% of execution time just on the return statement (which included dictionary construction). The optimized version shows the entire method execution time reduced from 69.9ms to 50.7ms total, with consistent 20-42% improvements across all test cases.

**Impact assessment:**
This optimization is particularly beneficial for high-frequency transaction status parsing scenarios, as evidenced by the consistent performance gains across various edge cases and batch operations in the test suite. The method maintains identical functionality while eliminating wasteful repeated work.
@codeflash-ai codeflash-ai bot requested a review from mashraf-222 November 13, 2025 16:39
@codeflash-ai codeflash-ai bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash labels Nov 13, 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