⚡️ Speed up method lbank.parse_transaction_status by 174%
#50
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
📄 174% (1.74x) speedup for
lbank.parse_transaction_statusinpython/ccxt/lbank.py⏱️ Runtime :
9.51 milliseconds→3.47 milliseconds(best of12runs)📝 Explanation and details
The optimized code achieves a 174% speedup through two key optimizations that eliminate repetitive overhead in hot path functions:
Key Optimizations
1. Dictionary Hoisting in
parse_transaction_status:statusesdictionary from inside the function to a module-level constant_LBANK_TRANSACTION_STATUSES2. Fast-path optimization for
safe_stringandsafe_value:isinstance(dictionary, dict)andkey in dictionarychecks before falling back to the slowerExchange.key_exists()methodExchange.key_exists()performs generic type checking, exception handling, and supports edge cases like lists with non-integer keys. For the common case of dictionary lookups, this is unnecessary overhead.safe_string, 13.07ms→6.77ms forsafe_value) by avoiding the generic fallback path.Performance Benefits by Test Case
The optimization shows consistent 70-200% speedups across all test scenarios:
These optimizations are particularly effective for transaction status parsing in cryptocurrency exchanges where the same status mappings are queried frequently during order processing and transaction monitoring workflows.
✅ Correctness verification report:
🌀 Generated Regression Tests and Runtime
import pytest
from ccxt.lbank import lbank
pytest fixture for the lbank instance
@pytest.fixture
def lbank_instance():
return lbank()
-------------------- BASIC TEST CASES --------------------
def test_deposit_status_pending(lbank_instance):
# Deposit status '1' should map to 'pending'
codeflash_output = lbank_instance.parse_transaction_status('1', 'deposit') # 3.37μs -> 1.97μs (71.0% faster)
def test_deposit_status_ok(lbank_instance):
# Deposit status '2' should map to 'ok'
codeflash_output = lbank_instance.parse_transaction_status('2', 'deposit') # 3.43μs -> 1.82μs (88.3% faster)
def test_deposit_status_failed(lbank_instance):
# Deposit status '3' should map to 'failed'
codeflash_output = lbank_instance.parse_transaction_status('3', 'deposit') # 3.41μs -> 1.84μs (85.6% faster)
def test_deposit_status_canceled(lbank_instance):
# Deposit status '4' should map to 'canceled'
codeflash_output = lbank_instance.parse_transaction_status('4', 'deposit') # 3.55μs -> 1.95μs (82.1% faster)
def test_deposit_status_transfer(lbank_instance):
# Deposit status '5' should map to 'transfer'
codeflash_output = lbank_instance.parse_transaction_status('5', 'deposit') # 3.46μs -> 1.90μs (82.0% faster)
def test_withdrawal_status_pending(lbank_instance):
# Withdrawal status '1' should map to 'pending'
codeflash_output = lbank_instance.parse_transaction_status('1', 'withdrawal') # 3.45μs -> 1.88μs (83.8% faster)
def test_withdrawal_status_canceled(lbank_instance):
# Withdrawal status '2' should map to 'canceled'
codeflash_output = lbank_instance.parse_transaction_status('2', 'withdrawal') # 3.35μs -> 1.86μs (80.6% faster)
def test_withdrawal_status_failed(lbank_instance):
# Withdrawal status '3' should map to 'failed'
codeflash_output = lbank_instance.parse_transaction_status('3', 'withdrawal') # 3.43μs -> 1.83μs (88.0% faster)
def test_withdrawal_status_ok(lbank_instance):
# Withdrawal status '4' should map to 'ok'
codeflash_output = lbank_instance.parse_transaction_status('4', 'withdrawal') # 3.40μs -> 1.93μs (76.3% faster)
-------------------- EDGE TEST CASES --------------------
def test_unknown_type_returns_status(lbank_instance):
# Unknown type should return the status unchanged
codeflash_output = lbank_instance.parse_transaction_status('1', 'unknown') # 3.47μs -> 1.54μs (126% faster)
codeflash_output = lbank_instance.parse_transaction_status('foo', 'unknown') # 1.35μs -> 531ns (155% faster)
codeflash_output = lbank_instance.parse_transaction_status('', 'unknown') # 1.04μs -> 316ns (229% faster)
def test_unknown_status_returns_status(lbank_instance):
# Unknown status for deposit should return the status unchanged
codeflash_output = lbank_instance.parse_transaction_status('999', 'deposit') # 3.55μs -> 1.66μs (115% faster)
# Unknown status for withdrawal should return the status unchanged
codeflash_output = lbank_instance.parse_transaction_status('999', 'withdrawal') # 1.50μs -> 578ns (160% faster)
def test_empty_status_and_type(lbank_instance):
# Empty status and type should return empty string
codeflash_output = lbank_instance.parse_transaction_status('', '') # 3.47μs -> 1.41μs (147% faster)
codeflash_output = lbank_instance.parse_transaction_status('', 'deposit') # 1.74μs -> 751ns (132% faster)
codeflash_output = lbank_instance.parse_transaction_status('', 'withdrawal') # 1.00μs -> 450ns (122% faster)
def test_none_status_and_type(lbank_instance):
# None status and type should return None for status, type not in mapping
codeflash_output = lbank_instance.parse_transaction_status(None, None) # 3.58μs -> 1.57μs (128% faster)
# None status with valid type should return None
codeflash_output = lbank_instance.parse_transaction_status(None, 'deposit') # 1.80μs -> 744ns (142% faster)
codeflash_output = lbank_instance.parse_transaction_status(None, 'withdrawal') # 1.07μs -> 380ns (182% faster)
def test_numeric_status_as_int(lbank_instance):
# Status as int should be converted to string and mapped
codeflash_output = lbank_instance.parse_transaction_status(1, 'deposit') # 3.59μs -> 1.58μs (127% faster)
codeflash_output = lbank_instance.parse_transaction_status(2, 'withdrawal') # 1.40μs -> 587ns (139% faster)
# Unknown int status
codeflash_output = lbank_instance.parse_transaction_status(999, 'deposit') # 1.04μs -> 423ns (147% faster)
def test_type_case_sensitivity(lbank_instance):
# Type is case sensitive, so 'Deposit' is not recognized
codeflash_output = lbank_instance.parse_transaction_status('1', 'Deposit') # 3.55μs -> 1.60μs (122% faster)
codeflash_output = lbank_instance.parse_transaction_status('1', 'WITHDRAWAL') # 1.38μs -> 602ns (129% faster)
def test_status_case_sensitivity(lbank_instance):
# Status is case sensitive, so '1' is recognized, but '1 ' or '01' is not
codeflash_output = lbank_instance.parse_transaction_status('01', 'deposit') # 3.54μs -> 1.68μs (111% faster)
codeflash_output = lbank_instance.parse_transaction_status('1 ', 'deposit') # 1.45μs -> 520ns (179% faster)
codeflash_output = lbank_instance.parse_transaction_status('1', 'deposit') # 1.23μs -> 589ns (109% faster)
def test_status_as_non_string(lbank_instance):
# Status as other types (float, bool, list, dict)
codeflash_output = lbank_instance.parse_transaction_status(1.0, 'deposit')
codeflash_output = lbank_instance.parse_transaction_status(True, 'deposit')
codeflash_output = lbank_instance.parse_transaction_status([1], 'deposit')
codeflash_output = lbank_instance.parse_transaction_status({'foo': 'bar'}, 'deposit')
def test_type_as_non_string(lbank_instance):
# Type as non-string should not match mapping
codeflash_output = lbank_instance.parse_transaction_status('1', 123) # 3.51μs -> 1.61μs (118% faster)
codeflash_output = lbank_instance.parse_transaction_status('1', None) # 1.47μs -> 516ns (185% faster)
codeflash_output = lbank_instance.parse_transaction_status('1', True) # 1.10μs -> 379ns (192% faster)
-------------------- LARGE SCALE TEST CASES --------------------
def test_large_number_of_unknown_statuses(lbank_instance):
# Test performance and correctness for 1000 unknown statuses
for i in range(1000):
status = str(i + 1000) # All are unknown
codeflash_output = lbank_instance.parse_transaction_status(status, 'deposit') # 970μs -> 353μs (174% faster)
codeflash_output = lbank_instance.parse_transaction_status(status, 'withdrawal')
def test_large_number_of_known_statuses(lbank_instance):
# Test correctness for all known statuses repeated 200 times
known_deposit = ['1', '2', '3', '4', '5']
known_withdrawal = ['1', '2', '3', '4']
for i in range(200):
for status in known_deposit:
codeflash_output = lbank_instance.parse_transaction_status(status, 'deposit')
for status in known_withdrawal:
codeflash_output = lbank_instance.parse_transaction_status(status, 'withdrawal')
def test_large_number_of_random_types(lbank_instance):
# Test with 500 random types, all should return status unchanged
for i in range(500):
type_str = f"random_type_{i}"
codeflash_output = lbank_instance.parse_transaction_status('1', type_str) # 501μs -> 165μs (204% faster)
codeflash_output = lbank_instance.parse_transaction_status('foo', type_str)
def test_large_number_of_empty_statuses(lbank_instance):
# Test with 500 empty statuses
for i in range(500):
codeflash_output = lbank_instance.parse_transaction_status('', 'deposit') # 461μs -> 155μs (197% faster)
codeflash_output = lbank_instance.parse_transaction_status('', 'withdrawal')
codeflash_output = lbank_instance.parse_transaction_status('', f"random_type_{i}") # 457μs -> 153μs (197% faster)
def test_large_number_of_none_statuses(lbank_instance):
# Test with 500 None statuses
for i in range(500):
codeflash_output = lbank_instance.parse_transaction_status(None, 'deposit') # 461μs -> 157μs (193% faster)
codeflash_output = lbank_instance.parse_transaction_status(None, 'withdrawal')
codeflash_output = lbank_instance.parse_transaction_status(None, f"random_type_{i}") # 459μs -> 154μs (197% faster)
-------------------- MUTATION TESTING GUARD --------------------
def test_mutation_guard_for_deposit(lbank_instance):
# If mapping changes, this should fail
codeflash_output = lbank_instance.parse_transaction_status('1', 'deposit') # 3.31μs -> 1.84μs (79.2% faster)
codeflash_output = lbank_instance.parse_transaction_status('2', 'deposit') # 1.37μs -> 665ns (106% faster)
codeflash_output = lbank_instance.parse_transaction_status('3', 'deposit') # 977ns -> 436ns (124% faster)
codeflash_output = lbank_instance.parse_transaction_status('4', 'deposit') # 991ns -> 403ns (146% faster)
codeflash_output = lbank_instance.parse_transaction_status('5', 'deposit') # 912ns -> 352ns (159% faster)
def test_mutation_guard_for_withdrawal(lbank_instance):
# If mapping changes, this should fail
codeflash_output = lbank_instance.parse_transaction_status('1', 'withdrawal') # 3.16μs -> 1.84μs (71.7% faster)
codeflash_output = lbank_instance.parse_transaction_status('2', 'withdrawal') # 1.47μs -> 675ns (117% faster)
codeflash_output = lbank_instance.parse_transaction_status('3', 'withdrawal') # 1.04μs -> 411ns (154% faster)
codeflash_output = lbank_instance.parse_transaction_status('4', 'withdrawal') # 1.00μs -> 354ns (183% faster)
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.lbank import lbank
Create a fixture for the lbank instance
@pytest.fixture
def lbank_instance():
return lbank()
-------------------- Basic Test Cases --------------------
def test_deposit_status_pending(lbank_instance):
# Basic: deposit status '1' should be 'pending'
codeflash_output = lbank_instance.parse_transaction_status('1', 'deposit') # 3.37μs -> 1.77μs (90.9% faster)
def test_deposit_status_ok(lbank_instance):
# Basic: deposit status '2' should be 'ok'
codeflash_output = lbank_instance.parse_transaction_status('2', 'deposit') # 3.37μs -> 1.86μs (80.8% faster)
def test_deposit_status_failed(lbank_instance):
# Basic: deposit status '3' should be 'failed'
codeflash_output = lbank_instance.parse_transaction_status('3', 'deposit') # 3.51μs -> 1.93μs (81.7% faster)
def test_deposit_status_canceled(lbank_instance):
# Basic: deposit status '4' should be 'canceled'
codeflash_output = lbank_instance.parse_transaction_status('4', 'deposit') # 3.41μs -> 1.91μs (78.8% faster)
def test_deposit_status_transfer(lbank_instance):
# Basic: deposit status '5' should be 'transfer'
codeflash_output = lbank_instance.parse_transaction_status('5', 'deposit') # 3.46μs -> 1.88μs (83.7% faster)
def test_withdrawal_status_pending(lbank_instance):
# Basic: withdrawal status '1' should be 'pending'
codeflash_output = lbank_instance.parse_transaction_status('1', 'withdrawal') # 3.22μs -> 1.86μs (72.6% faster)
def test_withdrawal_status_canceled(lbank_instance):
# Basic: withdrawal status '2' should be 'canceled'
codeflash_output = lbank_instance.parse_transaction_status('2', 'withdrawal') # 3.33μs -> 1.89μs (76.4% faster)
def test_withdrawal_status_failed(lbank_instance):
# Basic: withdrawal status '3' should be 'failed'
codeflash_output = lbank_instance.parse_transaction_status('3', 'withdrawal') # 3.29μs -> 1.94μs (69.9% faster)
def test_withdrawal_status_ok(lbank_instance):
# Basic: withdrawal status '4' should be 'ok'
codeflash_output = lbank_instance.parse_transaction_status('4', 'withdrawal') # 3.34μs -> 1.77μs (89.2% faster)
-------------------- Edge Test Cases --------------------
def test_unknown_status_in_deposit(lbank_instance):
# Edge: Unknown status code in deposit should return the status code itself
codeflash_output = lbank_instance.parse_transaction_status('999', 'deposit') # 3.51μs -> 1.46μs (141% faster)
def test_unknown_status_in_withdrawal(lbank_instance):
# Edge: Unknown status code in withdrawal should return the status code itself
codeflash_output = lbank_instance.parse_transaction_status('999', 'withdrawal') # 3.71μs -> 1.69μs (119% faster)
def test_unknown_type(lbank_instance):
# Edge: Unknown type should return the status code itself
codeflash_output = lbank_instance.parse_transaction_status('1', 'foobar') # 3.49μs -> 1.42μs (145% faster)
def test_none_status(lbank_instance):
# Edge: None as status should return None
codeflash_output = lbank_instance.parse_transaction_status(None, 'deposit') # 3.43μs -> 1.70μs (101% faster)
def test_none_type(lbank_instance):
# Edge: None as type should return the status code itself
codeflash_output = lbank_instance.parse_transaction_status('1', None) # 3.45μs -> 1.65μs (109% faster)
def test_empty_string_status(lbank_instance):
# Edge: Empty string as status should return empty string
codeflash_output = lbank_instance.parse_transaction_status('', 'deposit') # 3.44μs -> 1.62μs (112% faster)
def test_empty_string_type(lbank_instance):
# Edge: Empty string as type should return the status code itself
codeflash_output = lbank_instance.parse_transaction_status('1', '') # 3.29μs -> 1.46μs (126% faster)
def test_status_as_int_string(lbank_instance):
# Edge: Status given as an integer string, should match string keys
codeflash_output = lbank_instance.parse_transaction_status(str(2), 'deposit') # 3.49μs -> 1.87μs (86.7% faster)
def test_status_as_int(lbank_instance):
# Edge: Status given as an integer, should return the integer itself (no match)
codeflash_output = lbank_instance.parse_transaction_status(2, 'deposit') # 3.70μs -> 1.71μs (117% faster)
def test_type_case_sensitivity(lbank_instance):
# Edge: Type is case-sensitive, so 'Deposit' should not match 'deposit'
codeflash_output = lbank_instance.parse_transaction_status('1', 'Deposit') # 3.43μs -> 1.57μs (118% faster)
def test_status_case_sensitivity(lbank_instance):
# Edge: Status is case-sensitive, so '1' != '1 ' or '01'
codeflash_output = lbank_instance.parse_transaction_status('01', 'deposit') # 3.55μs -> 1.80μs (97.4% faster)
codeflash_output = lbank_instance.parse_transaction_status('1 ', 'deposit') # 1.49μs -> 577ns (158% faster)
def test_status_zero(lbank_instance):
# Edge: Status '0' is not mapped; should return '0'
codeflash_output = lbank_instance.parse_transaction_status('0', 'deposit') # 3.57μs -> 1.64μs (118% faster)
codeflash_output = lbank_instance.parse_transaction_status('0', 'withdrawal') # 1.34μs -> 610ns (120% faster)
def test_type_numeric(lbank_instance):
# Edge: Type as integer should return status itself (no match)
codeflash_output = lbank_instance.parse_transaction_status('1', 123) # 3.43μs -> 1.58μs (117% faster)
def test_status_boolean(lbank_instance):
# Edge: Status as boolean should return the boolean itself (no match)
codeflash_output = lbank_instance.parse_transaction_status(True, 'deposit') # 3.51μs -> 1.59μs (120% faster)
codeflash_output = lbank_instance.parse_transaction_status(False, 'withdrawal') # 1.40μs -> 633ns (121% faster)
def test_type_boolean(lbank_instance):
# Edge: Type as boolean should return status itself (no match)
codeflash_output = lbank_instance.parse_transaction_status('1', True) # 3.54μs -> 1.58μs (123% faster)
codeflash_output = lbank_instance.parse_transaction_status('1', False) # 1.40μs -> 566ns (148% faster)
def test_both_none(lbank_instance):
# Edge: Both status and type are None; should return None
codeflash_output = lbank_instance.parse_transaction_status(None, None) # 3.62μs -> 1.57μs (130% faster)
def test_both_empty(lbank_instance):
# Edge: Both status and type are empty string; should return empty string
codeflash_output = lbank_instance.parse_transaction_status('', '') # 3.21μs -> 1.54μs (108% faster)
def test_all_deposit_statuses(lbank_instance):
# Large: Check all mapped and unmapped deposit statuses in a batch
known = {'1': 'pending', '2': 'ok', '3': 'failed', '4': 'canceled', '5': 'transfer'}
for i in range(1, 11):
key = str(i)
expected = known[key] if key in known else key
codeflash_output = lbank_instance.parse_transaction_status(key, 'deposit') # 12.9μs -> 5.70μs (126% faster)
def test_all_withdrawal_statuses(lbank_instance):
# Large: Check all mapped and unmapped withdrawal statuses in a batch
known = {'1': 'pending', '2': 'canceled', '3': 'failed', '4': 'ok'}
for i in range(1, 11):
key = str(i)
expected = known[key] if key in known else key
codeflash_output = lbank_instance.parse_transaction_status(key, 'withdrawal') # 12.3μs -> 5.52μs (123% faster)
def test_large_batch_unknown_types(lbank_instance):
# Large: 100 unknown types, all should return status as is
for i in range(100):
status = str(i)
type_ = f'unknown_type_{i}'
codeflash_output = lbank_instance.parse_transaction_status(status, type_) # 108μs -> 36.0μs (201% faster)
def test_large_batch_random_statuses_and_types(lbank_instance):
# Large: 1000 random status/type combinations, most should return status as is
for i in range(1000):
status = str(i % 7) # only 1-5 are mapped for deposit, 1-4 for withdrawal
type_ = 'deposit' if i % 2 == 0 else 'withdrawal'
# Expected value
if type_ == 'deposit':
expected = {
'1': 'pending',
'2': 'ok',
'3': 'failed',
'4': 'canceled',
'5': 'transfer',
}.get(status, status)
else:
expected = {
'1': 'pending',
'2': 'canceled',
'3': 'failed',
'4': 'ok',
}.get(status, status)
codeflash_output = lbank_instance.parse_transaction_status(status, type_) # 927μs -> 359μs (158% faster)
def test_performance_large_input(lbank_instance):
# Large: Performance test for 1000 calls (should be fast)
results = []
for i in range(1000):
results.append(lbank_instance.parse_transaction_status(str(i % 5 + 1), 'deposit')) # 902μs -> 367μs (145% faster)
def test_large_batch_edge_types(lbank_instance):
# Large: 1000 calls with edge-case types (None, int, bool, float, empty string)
edge_types = [None, 123, True, False, '', [], {}, 0.0]
for i in range(1000):
status = str(i % 10)
type_ = edge_types[i % len(edge_types)]
codeflash_output = lbank_instance.parse_transaction_status(status, type_)
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-mhvk1dq2and push.