0
# Data Formatting
1
2
Advanced data transformation utilities including formatters, applicators, and functional programming tools for complex data processing workflows.
3
4
## Capabilities
5
6
### Formatter Application
7
8
Apply formatting functions to data structures with precise control.
9
10
```python { .api }
11
def apply_formatter_if(condition, formatter, value):
12
"""
13
Conditionally apply formatter based on condition function.
14
15
Args:
16
condition: Function that returns bool when passed value
17
formatter: Function to apply if condition is True
18
value: Value to potentially format
19
20
Returns:
21
Formatted value if condition is True, otherwise original value
22
"""
23
24
def apply_formatter_at_index(formatter, at_index, value):
25
"""
26
Apply formatter to element at specific index in sequence.
27
28
Args:
29
formatter: Function to apply to the element
30
at_index (int): Index of element to format
31
value: Sequence containing element to format
32
33
Returns:
34
Generator yielding formatted sequence
35
"""
36
37
def apply_formatter_to_array(formatter, value):
38
"""
39
Apply formatter to all elements in array.
40
41
Args:
42
formatter: Function to apply to each element
43
value: Iterable to format
44
45
Returns:
46
Generator yielding formatted elements
47
"""
48
```
49
50
### Dictionary Formatting
51
52
Transform dictionary structures with key mapping and value formatting.
53
54
```python { .api }
55
def apply_formatters_to_dict(formatters, value, unaliased=False):
56
"""
57
Apply formatters to dictionary values.
58
59
Args:
60
formatters: Dict mapping keys to formatter functions
61
value: Dictionary to format
62
unaliased (bool): Whether to process keys without aliasing
63
64
Returns:
65
Generator yielding formatted dictionary items
66
"""
67
68
def apply_key_map(key_mappings, value):
69
"""
70
Apply key transformations to dictionary.
71
72
Args:
73
key_mappings: Dict mapping old keys to new keys
74
value: Dictionary to transform
75
76
Returns:
77
Generator yielding transformed dictionary items
78
"""
79
```
80
81
### Sequence Formatting
82
83
Format sequences with multiple formatters.
84
85
```python { .api }
86
def apply_formatters_to_sequence(formatters, sequence):
87
"""
88
Apply corresponding formatters to sequence elements.
89
90
Args:
91
formatters: Sequence of formatter functions
92
sequence: Sequence to format
93
94
Returns:
95
Generator yielding formatted sequence elements
96
"""
97
98
def apply_one_of_formatters(formatter_condition_pairs, value):
99
"""
100
Apply first matching formatter from condition-formatter pairs.
101
102
Args:
103
formatter_condition_pairs: Sequence of (formatter, condition) tuples
104
value: Value to format
105
106
Returns:
107
Formatted value using first matching formatter
108
"""
109
```
110
111
## Usage Examples
112
113
### Conditional Formatting
114
115
```python
116
from eth_utils import apply_formatter_if, is_string, to_checksum_address
117
118
def format_address_if_string(value):
119
"""Format value as checksum address if it's a string."""
120
return apply_formatter_if(
121
condition=is_string,
122
formatter=to_checksum_address,
123
value=value
124
)
125
126
# Examples
127
addr1 = "0xd3cda913deb6f67967b99d67acdfa1712c293601" # String
128
addr2 = b'\xd3\xcd\xa9...' # Bytes
129
130
result1 = format_address_if_string(addr1) # Checksummed address
131
result2 = format_address_if_string(addr2) # Unchanged bytes
132
133
print(result1) # 0xd3CdA913deB6f67967B99D67aCDFa1712C293601
134
print(result2) # b'\xd3\xcd\xa9...'
135
```
136
137
### Array Processing
138
139
```python
140
from eth_utils import apply_formatter_to_array, to_int
141
142
def parse_hex_array(hex_strings):
143
"""Convert array of hex strings to integers."""
144
return list(apply_formatter_to_array(
145
formatter=lambda x: to_int(hexstr=x),
146
value=hex_strings
147
))
148
149
# Example
150
hex_values = ["0x1", "0xa", "0xff", "0x100"]
151
int_values = parse_hex_array(hex_values)
152
print(int_values) # [1, 10, 255, 256]
153
```
154
155
### Index-Specific Formatting
156
157
```python
158
from eth_utils import apply_formatter_at_index, to_checksum_address
159
160
def format_transaction_recipient(transaction_array):
161
"""Format the recipient address (index 2) in transaction array."""
162
return list(apply_formatter_at_index(
163
formatter=to_checksum_address,
164
at_index=2,
165
value=transaction_array
166
))
167
168
# Example transaction: [from, value, to, data]
169
tx = [
170
"0xsender...",
171
1000000000000000000, # 1 ETH in wei
172
"0xd3cda913deb6f67967b99d67acdfa1712c293601", # to address
173
"0x"
174
]
175
176
formatted_tx = format_transaction_recipient(tx)
177
print(formatted_tx[2]) # Checksummed address
178
```
179
180
### Dictionary Value Formatting
181
182
```python
183
from eth_utils import apply_formatters_to_dict, to_int, to_checksum_address
184
185
def format_transaction_dict(tx_dict):
186
"""Format transaction dictionary fields."""
187
formatters = {
188
'value': lambda x: to_int(hexstr=x),
189
'gasPrice': lambda x: to_int(hexstr=x),
190
'gasLimit': lambda x: to_int(hexstr=x),
191
'nonce': lambda x: to_int(hexstr=x),
192
'to': to_checksum_address,
193
'from': to_checksum_address
194
}
195
196
return dict(apply_formatters_to_dict(formatters, tx_dict))
197
198
# Example raw transaction
199
raw_tx = {
200
'value': '0xde0b6b3a7640000', # 1 ETH in hex
201
'gasPrice': '0x4a817c800', # 20 gwei in hex
202
'gasLimit': '0x5208', # 21000 in hex
203
'nonce': '0x1',
204
'to': '0xd3cda913deb6f67967b99d67acdfa1712c293601',
205
'from': '0x742d35cc6634c0532925a3b8c17b1e8b4e1d1123',
206
'data': '0x'
207
}
208
209
formatted_tx = format_transaction_dict(raw_tx)
210
print(formatted_tx['value']) # 1000000000000000000
211
print(formatted_tx['gasPrice']) # 20000000000
212
print(formatted_tx['to']) # Checksummed address
213
```
214
215
### Key Mapping
216
217
```python
218
from eth_utils import apply_key_map
219
220
def normalize_rpc_response(response):
221
"""Normalize RPC response field names."""
222
key_mappings = {
223
'blockHash': 'block_hash',
224
'blockNumber': 'block_number',
225
'transactionHash': 'transaction_hash',
226
'transactionIndex': 'transaction_index',
227
'gasUsed': 'gas_used',
228
'gasPrice': 'gas_price'
229
}
230
231
return dict(apply_key_map(key_mappings, response))
232
233
# Example RPC response
234
rpc_response = {
235
'blockHash': '0x123...',
236
'blockNumber': '0x1b4',
237
'transactionHash': '0x456...',
238
'gasUsed': '0x5208',
239
'status': '0x1'
240
}
241
242
normalized = normalize_rpc_response(rpc_response)
243
print(normalized)
244
# {
245
# 'block_hash': '0x123...',
246
# 'block_number': '0x1b4',
247
# 'transaction_hash': '0x456...',
248
# 'gas_used': '0x5208',
249
# 'status': '0x1'
250
# }
251
```
252
253
### Multiple Formatter Chains
254
255
```python
256
from eth_utils import apply_formatters_to_sequence, to_int, to_checksum_address, encode_hex
257
258
def format_transaction_tuple(tx_tuple):
259
"""Format transaction tuple with specific formatters for each field."""
260
# Transaction format: (nonce, gasPrice, gasLimit, to, value, data)
261
formatters = [
262
lambda x: to_int(hexstr=x), # nonce
263
lambda x: to_int(hexstr=x), # gasPrice
264
lambda x: to_int(hexstr=x), # gasLimit
265
to_checksum_address, # to
266
lambda x: to_int(hexstr=x), # value
267
lambda x: x if x == '0x' else encode_hex(bytes.fromhex(x[2:])) # data
268
]
269
270
return tuple(apply_formatters_to_sequence(formatters, tx_tuple))
271
272
# Example
273
raw_tx_tuple = (
274
'0x1', # nonce
275
'0x4a817c800', # gasPrice
276
'0x5208', # gasLimit
277
'0xd3cda913deb6f67967b99d67acdfa1712c293601', # to
278
'0xde0b6b3a7640000', # value
279
'0x' # data
280
)
281
282
formatted = format_transaction_tuple(raw_tx_tuple)
283
print(formatted)
284
```
285
286
### Conditional Multi-Formatter
287
288
```python
289
from eth_utils import apply_one_of_formatters, is_string, is_integer, to_int, encode_hex
290
291
def smart_hex_formatter(value):
292
"""Apply appropriate hex formatting based on value type."""
293
formatter_condition_pairs = [
294
(lambda x: encode_hex(x), lambda x: isinstance(x, int)),
295
(lambda x: to_int(hexstr=x), lambda x: is_string(x) and x.startswith('0x')),
296
(lambda x: x, lambda x: True) # Default: return as-is
297
]
298
299
return apply_one_of_formatters(formatter_condition_pairs, value)
300
301
# Examples
302
print(smart_hex_formatter(255)) # 0xff (int to hex)
303
print(smart_hex_formatter("0xff")) # 255 (hex to int)
304
print(smart_hex_formatter("text")) # "text" (unchanged)
305
```
306
307
### Complex Data Pipeline
308
309
```python
310
from eth_utils import (
311
apply_formatters_to_dict, apply_formatter_to_array,
312
to_int, to_checksum_address, is_string
313
)
314
315
def process_block_data(block_data):
316
"""Process raw block data from RPC."""
317
318
# Format block-level fields
319
block_formatters = {
320
'number': lambda x: to_int(hexstr=x),
321
'timestamp': lambda x: to_int(hexstr=x),
322
'gasLimit': lambda x: to_int(hexstr=x),
323
'gasUsed': lambda x: to_int(hexstr=x),
324
'miner': to_checksum_address
325
}
326
327
# Format the block
328
formatted_block = dict(apply_formatters_to_dict(block_formatters, block_data))
329
330
# Format transactions array if present
331
if 'transactions' in formatted_block:
332
tx_formatters = {
333
'value': lambda x: to_int(hexstr=x),
334
'gasPrice': lambda x: to_int(hexstr=x),
335
'gasLimit': lambda x: to_int(hexstr=x),
336
'nonce': lambda x: to_int(hexstr=x),
337
'to': lambda x: to_checksum_address(x) if x else None,
338
'from': to_checksum_address
339
}
340
341
# Apply formatters to each transaction
342
formatted_transactions = []
343
for tx in formatted_block['transactions']:
344
if isinstance(tx, dict): # Full transaction object
345
formatted_tx = dict(apply_formatters_to_dict(tx_formatters, tx))
346
formatted_transactions.append(formatted_tx)
347
else: # Transaction hash only
348
formatted_transactions.append(tx)
349
350
formatted_block['transactions'] = formatted_transactions
351
352
return formatted_block
353
354
# Example usage with raw block data
355
raw_block = {
356
'number': '0x1b4',
357
'timestamp': '0x61234567',
358
'gasLimit': '0x1c9c380',
359
'gasUsed': '0x5208',
360
'miner': '0x742d35cc6634c0532925a3b8c17b1e8b4e1d1123',
361
'transactions': [
362
{
363
'value': '0xde0b6b3a7640000',
364
'gasPrice': '0x4a817c800',
365
'gasLimit': '0x5208',
366
'nonce': '0x1',
367
'to': '0xd3cda913deb6f67967b99d67acdfa1712c293601',
368
'from': '0x742d35cc6634c0532925a3b8c17b1e8b4e1d1123'
369
}
370
]
371
}
372
373
processed_block = process_block_data(raw_block)
374
print(f"Block number: {processed_block['number']}")
375
print(f"Gas used: {processed_block['gasUsed']}")
376
print(f"Transaction value: {processed_block['transactions'][0]['value']}")
377
```
378
379
## Advanced Patterns
380
381
### Custom Formatter Classes
382
383
```python
384
from eth_utils import apply_formatter_if, is_string
385
386
class AddressFormatter:
387
"""Custom formatter for Ethereum addresses."""
388
389
def __init__(self, checksum=True):
390
self.checksum = checksum
391
392
def __call__(self, value):
393
if self.checksum:
394
return apply_formatter_if(is_string, to_checksum_address, value)
395
else:
396
return apply_formatter_if(is_string, str.lower, value)
397
398
# Usage
399
checksum_formatter = AddressFormatter(checksum=True)
400
lowercase_formatter = AddressFormatter(checksum=False)
401
402
addr = "0xD3CDA913DEB6F67967B99D67ACDFA1712C293601"
403
print(checksum_formatter(addr)) # Proper checksum
404
print(lowercase_formatter(addr)) # Lowercase
405
```