hexconv 0.2.3__tar.gz → 0.2.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hexconv-0.2.3/src/hexconv.egg-info → hexconv-0.2.5}/PKG-INFO +101 -97
- {hexconv-0.2.3 → hexconv-0.2.5}/README.md +100 -96
- {hexconv-0.2.3 → hexconv-0.2.5}/pyproject.toml +1 -1
- {hexconv-0.2.3 → hexconv-0.2.5/src/hexconv.egg-info}/PKG-INFO +101 -97
- {hexconv-0.2.3 → hexconv-0.2.5}/tests/test_hexconv.py +52 -3
- {hexconv-0.2.3 → hexconv-0.2.5}/LICENSE +0 -0
- {hexconv-0.2.3 → hexconv-0.2.5}/MANIFEST.in +0 -0
- {hexconv-0.2.3 → hexconv-0.2.5}/setup.cfg +0 -0
- {hexconv-0.2.3 → hexconv-0.2.5}/src/hexconv/__init__.py +0 -0
- {hexconv-0.2.3 → hexconv-0.2.5}/src/hexconv/_core.py +0 -0
- {hexconv-0.2.3 → hexconv-0.2.5}/src/hexconv/py.typed +0 -0
- {hexconv-0.2.3 → hexconv-0.2.5}/src/hexconv.egg-info/SOURCES.txt +0 -0
- {hexconv-0.2.3 → hexconv-0.2.5}/src/hexconv.egg-info/dependency_links.txt +0 -0
- {hexconv-0.2.3 → hexconv-0.2.5}/src/hexconv.egg-info/requires.txt +0 -0
- {hexconv-0.2.3 → hexconv-0.2.5}/src/hexconv.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hexconv
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.5
|
|
4
4
|
Summary: Pythonic conversion toolkit for bytes, hex, integers, arrays, binary strings, base64, and text.
|
|
5
5
|
Author: hexconv contributors
|
|
6
6
|
License-Expression: MIT
|
|
@@ -41,64 +41,99 @@ It is built around ergonomic one-liners and composable format objects.
|
|
|
41
41
|
pip install hexconv
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
##
|
|
44
|
+
## Simple usage
|
|
45
45
|
|
|
46
|
-
Use
|
|
46
|
+
Most conversions are one-liners. Use `from_auto` when you want a quick
|
|
47
|
+
best-effort parse, or pick an explicit helper when the input is ambiguous.
|
|
47
48
|
|
|
48
49
|
```python
|
|
49
50
|
import hexconv as hx
|
|
50
51
|
|
|
51
|
-
hx.
|
|
52
|
-
#
|
|
52
|
+
hx.from_auto("0x64617461").text
|
|
53
|
+
# 'data'
|
|
53
54
|
|
|
54
|
-
hx.
|
|
55
|
-
#
|
|
55
|
+
hx.from_bytes_array([0xde, 0xad, 0xbe, 0xef]).int
|
|
56
|
+
# 3735928559
|
|
56
57
|
|
|
57
|
-
hx.
|
|
58
|
-
# '
|
|
58
|
+
hx.from_text("data").hex
|
|
59
|
+
# '64617461'
|
|
60
|
+
```
|
|
59
61
|
|
|
60
|
-
|
|
61
|
-
# 'deadbeef'
|
|
62
|
+
## Fast compose
|
|
62
63
|
|
|
63
|
-
|
|
64
|
-
|
|
64
|
+
Create your own converters by snapping together
|
|
65
|
+
`source format >> optional transforms >> target format`.
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
```python
|
|
68
|
+
to_bytes = hx.Hex() >> hx.Bytes()
|
|
69
|
+
to_bytes("68 69")
|
|
70
|
+
# b'hi'
|
|
68
71
|
|
|
69
|
-
hx.
|
|
70
|
-
|
|
72
|
+
spaced_hex = hx.Bytes() >> hx.Hex(sep=" ")
|
|
73
|
+
spaced_hex(b"data")
|
|
74
|
+
# '64 61 74 61'
|
|
75
|
+
|
|
76
|
+
words = hx.Hex() >> hx.Chunk(2) >> hx.IntArray()
|
|
77
|
+
words("12 34 56 78")
|
|
78
|
+
# [4660, 22136]
|
|
79
|
+
|
|
80
|
+
pack_to_hex = hx.Struct(">HH") >> hx.Hex()
|
|
81
|
+
pack_to_hex((0x1234, 0x5678))
|
|
82
|
+
# '12345678'
|
|
71
83
|
```
|
|
72
84
|
|
|
73
|
-
|
|
85
|
+
## Configure when needed
|
|
86
|
+
|
|
87
|
+
Formats work bare by default. Add arguments only for the conversion that needs
|
|
88
|
+
them:
|
|
74
89
|
|
|
75
90
|
```python
|
|
76
|
-
hx.
|
|
91
|
+
hx.convert("de ad be ef", hx.Hex(), hx.Bytes())
|
|
77
92
|
# b'\xde\xad\xbe\xef'
|
|
78
93
|
|
|
79
|
-
hx.
|
|
80
|
-
# '
|
|
94
|
+
hx.convert(b"\xde\xad\xbe\xef", hx.Bytes(), hx.Hex(sep=" ", prefix=True, uppercase=True))
|
|
95
|
+
# '0xDE AD BE EF'
|
|
96
|
+
|
|
97
|
+
hx.convert("π", hx.Text(encoding="utf-8"), hx.Hex())
|
|
98
|
+
# 'cf80'
|
|
81
99
|
|
|
82
|
-
hx.
|
|
83
|
-
# '
|
|
100
|
+
hx.from_int(0x12345678, endian="little").hex
|
|
101
|
+
# '78563412'
|
|
102
|
+
|
|
103
|
+
hx.convert("ZGF0YQ", hx.Base64(padding=False), hx.Text())
|
|
104
|
+
# 'data'
|
|
105
|
+
|
|
106
|
+
hx.from_binary("00010110 10010110", bit_order="lsb").text
|
|
107
|
+
# 'hi'
|
|
84
108
|
```
|
|
85
109
|
|
|
86
|
-
|
|
110
|
+
Hex strings may include common separators, so you do not need to manually strip
|
|
111
|
+
spaces, colons, dashes, or `0x` prefixes before converting. `Hex(sep=" ")` is
|
|
112
|
+
how you emit space-separated hex.
|
|
113
|
+
|
|
114
|
+
## Full pipeline guide
|
|
87
115
|
|
|
88
116
|
`hexconv` is built around small format objects. A format can parse directly:
|
|
89
117
|
|
|
90
118
|
```python
|
|
91
|
-
hx.Hex()("
|
|
119
|
+
hx.Hex()("de ad be ef").bytes
|
|
92
120
|
# b'\xde\xad\xbe\xef'
|
|
93
121
|
|
|
94
122
|
hx.Text()("data").hex
|
|
95
123
|
# '64617461'
|
|
96
124
|
|
|
97
|
-
hx.Int(
|
|
125
|
+
hx.Int(endian="little")(0x12345678).hex
|
|
98
126
|
# '78563412'
|
|
127
|
+
|
|
128
|
+
pack_words = hx.Struct(">HH")
|
|
129
|
+
pack_words((0x1234, 0x5678)).hex
|
|
130
|
+
# '12345678'
|
|
131
|
+
|
|
132
|
+
hx.Hex()("12345678").to(pack_words)
|
|
133
|
+
# (4660, 22136)
|
|
99
134
|
```
|
|
100
135
|
|
|
101
|
-
Formats compose with
|
|
136
|
+
Formats compose with `>>`, so reusable converters are normal Python objects:
|
|
102
137
|
|
|
103
138
|
```python
|
|
104
139
|
to_text = hx.HexArray() >> hx.Text()
|
|
@@ -108,12 +143,20 @@ to_text([0x48, 0x65, 0x6C, 0x6C, 0x6F])
|
|
|
108
143
|
to_hex = hx.Text() >> hx.Hex(prefix=True)
|
|
109
144
|
to_hex("data")
|
|
110
145
|
# '0x64617461'
|
|
146
|
+
|
|
147
|
+
pack_to_hex = hx.Struct(">HH") >> hx.Hex()
|
|
148
|
+
pack_to_hex((0x1234, 0x5678))
|
|
149
|
+
# '12345678'
|
|
150
|
+
|
|
151
|
+
unpack_from_hex = hx.Hex() >> hx.Struct(">HH")
|
|
152
|
+
unpack_from_hex("12345678")
|
|
153
|
+
# (4660, 22136)
|
|
111
154
|
```
|
|
112
155
|
|
|
113
156
|
Transforms sit between formats when data needs shaping:
|
|
114
157
|
|
|
115
158
|
```python
|
|
116
|
-
words = hx.Hex() >> hx.Chunk(2) >> hx.IntArray(
|
|
159
|
+
words = hx.Hex() >> hx.Chunk(2) >> hx.IntArray()
|
|
117
160
|
words("12345678")
|
|
118
161
|
# [4660, 22136]
|
|
119
162
|
|
|
@@ -140,30 +183,7 @@ conv("12345678")
|
|
|
140
183
|
# ['0x1234', '0x5678']
|
|
141
184
|
```
|
|
142
185
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
Use `convert` when you want an explicit source and target in one expression:
|
|
146
|
-
|
|
147
|
-
```python
|
|
148
|
-
hx.convert("de ad be ef", hx.Hex(sep=" "), hx.Bytes())
|
|
149
|
-
# b'\xde\xad\xbe\xef'
|
|
150
|
-
|
|
151
|
-
hx.convert("data", hx.Text(), hx.Hex(prefix=True))
|
|
152
|
-
# '0x64617461'
|
|
153
|
-
|
|
154
|
-
hx.convert("π", hx.Text(encoding="utf-8"), hx.Hex())
|
|
155
|
-
# 'cf80'
|
|
156
|
-
|
|
157
|
-
hx.convert("-_8", hx.Base64(urlsafe=True, padding=False), hx.Hex())
|
|
158
|
-
# 'fbff'
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
Hex strings may include common separators, so you do not need to manually strip
|
|
162
|
-
spaces, colons, dashes, or `0x` prefixes before converting.
|
|
163
|
-
|
|
164
|
-
## Common conversion patterns
|
|
165
|
-
|
|
166
|
-
Text, bytes, and hex:
|
|
186
|
+
More conversion patterns:
|
|
167
187
|
|
|
168
188
|
```python
|
|
169
189
|
hx.Text()("hello").bytes
|
|
@@ -172,54 +192,24 @@ hx.Text()("hello").bytes
|
|
|
172
192
|
hx.Hex()("68656c6c6f").text
|
|
173
193
|
# 'hello'
|
|
174
194
|
|
|
175
|
-
hx.BytesArray()([
|
|
176
|
-
# '
|
|
177
|
-
```
|
|
195
|
+
hx.BytesArray()([0x4F, 0x4B]).to(hx.Text())
|
|
196
|
+
# 'OK'
|
|
178
197
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
```python
|
|
182
|
-
hx.Int(width=2)(0x1234).hex
|
|
183
|
-
# '1234'
|
|
184
|
-
|
|
185
|
-
hx.Int(width=2, endian="little")(0x1234).hex
|
|
198
|
+
hx.Int(endian="little")(0x1234).hex
|
|
186
199
|
# '3412'
|
|
187
200
|
|
|
188
|
-
(hx.Hex() >> hx.Chunk(2) >> hx.IntArray(width=2))("12345678")
|
|
189
|
-
# [4660, 22136]
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
Base encodings:
|
|
193
|
-
|
|
194
|
-
```python
|
|
195
|
-
hx.Text()("data").to(hx.Base64())
|
|
196
|
-
# 'ZGF0YQ=='
|
|
197
|
-
|
|
198
201
|
hx.Text()("data").to(hx.Base32(padding=False))
|
|
199
202
|
# 'MRQXIYI'
|
|
200
203
|
|
|
201
|
-
hx.
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
Escaped strings, hexdumps, structs, and bits:
|
|
206
|
-
|
|
207
|
-
```python
|
|
208
|
-
hx.Escaped()(r"\xde\xad").hex
|
|
209
|
-
# 'dead'
|
|
210
|
-
|
|
211
|
-
dump = hx.Hex()("deadbeef").to(hx.Hexdump(width=2))
|
|
212
|
-
hx.Hexdump()(dump).hex
|
|
213
|
-
# 'deadbeef'
|
|
214
|
-
|
|
215
|
-
hx.Struct(">HH")((0x1234, 0x5678)).hex
|
|
216
|
-
# '12345678'
|
|
204
|
+
dump = hx.Text()("data").to(hx.Hexdump(width=2))
|
|
205
|
+
hx.Hexdump()(dump).text
|
|
206
|
+
# 'data'
|
|
217
207
|
|
|
218
208
|
hx.Hex()("12345678").to(hx.Struct(">HH"))
|
|
219
209
|
# (4660, 22136)
|
|
220
210
|
|
|
221
|
-
hx.Bits()(
|
|
222
|
-
# '
|
|
211
|
+
hx.Bits()("0100111101001011").text
|
|
212
|
+
# 'OK'
|
|
223
213
|
```
|
|
224
214
|
|
|
225
215
|
## Why explicit formats?
|
|
@@ -267,10 +257,10 @@ result.reason
|
|
|
267
257
|
`from_auto(..., explain=True)` returns the same explanation object:
|
|
268
258
|
|
|
269
259
|
```python
|
|
270
|
-
result = hx.from_auto("
|
|
260
|
+
result = hx.from_auto("0b0100111101001011", explain=True)
|
|
271
261
|
|
|
272
|
-
result.value.
|
|
273
|
-
# '
|
|
262
|
+
result.value.text
|
|
263
|
+
# 'OK'
|
|
274
264
|
```
|
|
275
265
|
|
|
276
266
|
## Design priorities
|
|
@@ -294,7 +284,7 @@ conv("deadbeef")
|
|
|
294
284
|
# 3735928559
|
|
295
285
|
```
|
|
296
286
|
|
|
297
|
-
Available format specs:
|
|
287
|
+
Available format specs all work in their simplest bare form:
|
|
298
288
|
|
|
299
289
|
- `Bytes()`
|
|
300
290
|
- `BytesArray()`
|
|
@@ -302,8 +292,8 @@ Available format specs:
|
|
|
302
292
|
- `Hex()`
|
|
303
293
|
- `HexArray()`
|
|
304
294
|
- `HexInt()` / `LargeHexNumber()`
|
|
305
|
-
- `Int()`
|
|
306
|
-
- `IntArray()`
|
|
295
|
+
- `Int()` / `DecimalInt()`
|
|
296
|
+
- `IntArray()` / `DecimalIntArray()`
|
|
307
297
|
- `Text()`
|
|
308
298
|
- `Binary()`
|
|
309
299
|
- `Base64()`
|
|
@@ -314,6 +304,20 @@ Available format specs:
|
|
|
314
304
|
- `Hexdump()`
|
|
315
305
|
- `Struct(fmt)`
|
|
316
306
|
- `Bits()`
|
|
307
|
+
- `Auto()`
|
|
308
|
+
|
|
309
|
+
Add options only when you need control over formatting or parsing:
|
|
310
|
+
|
|
311
|
+
- Display: `Hex(sep=" ", prefix=True, uppercase=True)`, `HexArray(width=2)`.
|
|
312
|
+
- Integer packing: `Int(width=4)`, `Int(endian="little")`, `IntArray(width=2)`.
|
|
313
|
+
- Text: `Text(encoding="utf-8", errors="replace")`.
|
|
314
|
+
- Base encodings: `Base64(urlsafe=True, padding=False)`, `Base32(padding=False)`.
|
|
315
|
+
- Binary/bits: `Binary(sep=" ", prefix=True, bit_order="lsb")`, `Bits(pad_side="right")`.
|
|
316
|
+
- Dumps/escapes/structs: `Hexdump(width=8)`, `Escaped(uppercase=True)`, `Struct(">HH")`.
|
|
317
|
+
|
|
318
|
+
Some options only matter in one direction. For example, `Hex(sep=" ")`
|
|
319
|
+
controls hex output formatting, while hex input already accepts common
|
|
320
|
+
separators such as spaces, colons, dashes, underscores, and `0x` prefixes.
|
|
317
321
|
|
|
318
322
|
## Transforms
|
|
319
323
|
|
|
@@ -321,7 +325,7 @@ Transforms are byte-to-byte steps that sit between input and output formats.
|
|
|
321
325
|
|
|
322
326
|
```python
|
|
323
327
|
hx.Hex() >> hx.Chunk(2) >> hx.HexArray()
|
|
324
|
-
hx.Hex() >> hx.Group(2) >> hx.IntArray(
|
|
328
|
+
hx.Hex() >> hx.Group(2) >> hx.IntArray()
|
|
325
329
|
hx.Hex() >> hx.Pad.left(width=8) >> hx.Hex()
|
|
326
330
|
hx.Hex() >> hx.Pad.right(block_size=8, byte=0xFF) >> hx.Hex()
|
|
327
331
|
hx.Hex() >> hx.Reverse() >> hx.Hex()
|
|
@@ -12,64 +12,99 @@ It is built around ergonomic one-liners and composable format objects.
|
|
|
12
12
|
pip install hexconv
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
##
|
|
15
|
+
## Simple usage
|
|
16
16
|
|
|
17
|
-
Use
|
|
17
|
+
Most conversions are one-liners. Use `from_auto` when you want a quick
|
|
18
|
+
best-effort parse, or pick an explicit helper when the input is ambiguous.
|
|
18
19
|
|
|
19
20
|
```python
|
|
20
21
|
import hexconv as hx
|
|
21
22
|
|
|
22
|
-
hx.
|
|
23
|
-
#
|
|
23
|
+
hx.from_auto("0x64617461").text
|
|
24
|
+
# 'data'
|
|
24
25
|
|
|
25
|
-
hx.
|
|
26
|
-
#
|
|
26
|
+
hx.from_bytes_array([0xde, 0xad, 0xbe, 0xef]).int
|
|
27
|
+
# 3735928559
|
|
27
28
|
|
|
28
|
-
hx.
|
|
29
|
-
# '
|
|
29
|
+
hx.from_text("data").hex
|
|
30
|
+
# '64617461'
|
|
31
|
+
```
|
|
30
32
|
|
|
31
|
-
|
|
32
|
-
# 'deadbeef'
|
|
33
|
+
## Fast compose
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
Create your own converters by snapping together
|
|
36
|
+
`source format >> optional transforms >> target format`.
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
```python
|
|
39
|
+
to_bytes = hx.Hex() >> hx.Bytes()
|
|
40
|
+
to_bytes("68 69")
|
|
41
|
+
# b'hi'
|
|
39
42
|
|
|
40
|
-
hx.
|
|
41
|
-
|
|
43
|
+
spaced_hex = hx.Bytes() >> hx.Hex(sep=" ")
|
|
44
|
+
spaced_hex(b"data")
|
|
45
|
+
# '64 61 74 61'
|
|
46
|
+
|
|
47
|
+
words = hx.Hex() >> hx.Chunk(2) >> hx.IntArray()
|
|
48
|
+
words("12 34 56 78")
|
|
49
|
+
# [4660, 22136]
|
|
50
|
+
|
|
51
|
+
pack_to_hex = hx.Struct(">HH") >> hx.Hex()
|
|
52
|
+
pack_to_hex((0x1234, 0x5678))
|
|
53
|
+
# '12345678'
|
|
42
54
|
```
|
|
43
55
|
|
|
44
|
-
|
|
56
|
+
## Configure when needed
|
|
57
|
+
|
|
58
|
+
Formats work bare by default. Add arguments only for the conversion that needs
|
|
59
|
+
them:
|
|
45
60
|
|
|
46
61
|
```python
|
|
47
|
-
hx.
|
|
62
|
+
hx.convert("de ad be ef", hx.Hex(), hx.Bytes())
|
|
48
63
|
# b'\xde\xad\xbe\xef'
|
|
49
64
|
|
|
50
|
-
hx.
|
|
51
|
-
# '
|
|
65
|
+
hx.convert(b"\xde\xad\xbe\xef", hx.Bytes(), hx.Hex(sep=" ", prefix=True, uppercase=True))
|
|
66
|
+
# '0xDE AD BE EF'
|
|
67
|
+
|
|
68
|
+
hx.convert("π", hx.Text(encoding="utf-8"), hx.Hex())
|
|
69
|
+
# 'cf80'
|
|
52
70
|
|
|
53
|
-
hx.
|
|
54
|
-
# '
|
|
71
|
+
hx.from_int(0x12345678, endian="little").hex
|
|
72
|
+
# '78563412'
|
|
73
|
+
|
|
74
|
+
hx.convert("ZGF0YQ", hx.Base64(padding=False), hx.Text())
|
|
75
|
+
# 'data'
|
|
76
|
+
|
|
77
|
+
hx.from_binary("00010110 10010110", bit_order="lsb").text
|
|
78
|
+
# 'hi'
|
|
55
79
|
```
|
|
56
80
|
|
|
57
|
-
|
|
81
|
+
Hex strings may include common separators, so you do not need to manually strip
|
|
82
|
+
spaces, colons, dashes, or `0x` prefixes before converting. `Hex(sep=" ")` is
|
|
83
|
+
how you emit space-separated hex.
|
|
84
|
+
|
|
85
|
+
## Full pipeline guide
|
|
58
86
|
|
|
59
87
|
`hexconv` is built around small format objects. A format can parse directly:
|
|
60
88
|
|
|
61
89
|
```python
|
|
62
|
-
hx.Hex()("
|
|
90
|
+
hx.Hex()("de ad be ef").bytes
|
|
63
91
|
# b'\xde\xad\xbe\xef'
|
|
64
92
|
|
|
65
93
|
hx.Text()("data").hex
|
|
66
94
|
# '64617461'
|
|
67
95
|
|
|
68
|
-
hx.Int(
|
|
96
|
+
hx.Int(endian="little")(0x12345678).hex
|
|
69
97
|
# '78563412'
|
|
98
|
+
|
|
99
|
+
pack_words = hx.Struct(">HH")
|
|
100
|
+
pack_words((0x1234, 0x5678)).hex
|
|
101
|
+
# '12345678'
|
|
102
|
+
|
|
103
|
+
hx.Hex()("12345678").to(pack_words)
|
|
104
|
+
# (4660, 22136)
|
|
70
105
|
```
|
|
71
106
|
|
|
72
|
-
Formats compose with
|
|
107
|
+
Formats compose with `>>`, so reusable converters are normal Python objects:
|
|
73
108
|
|
|
74
109
|
```python
|
|
75
110
|
to_text = hx.HexArray() >> hx.Text()
|
|
@@ -79,12 +114,20 @@ to_text([0x48, 0x65, 0x6C, 0x6C, 0x6F])
|
|
|
79
114
|
to_hex = hx.Text() >> hx.Hex(prefix=True)
|
|
80
115
|
to_hex("data")
|
|
81
116
|
# '0x64617461'
|
|
117
|
+
|
|
118
|
+
pack_to_hex = hx.Struct(">HH") >> hx.Hex()
|
|
119
|
+
pack_to_hex((0x1234, 0x5678))
|
|
120
|
+
# '12345678'
|
|
121
|
+
|
|
122
|
+
unpack_from_hex = hx.Hex() >> hx.Struct(">HH")
|
|
123
|
+
unpack_from_hex("12345678")
|
|
124
|
+
# (4660, 22136)
|
|
82
125
|
```
|
|
83
126
|
|
|
84
127
|
Transforms sit between formats when data needs shaping:
|
|
85
128
|
|
|
86
129
|
```python
|
|
87
|
-
words = hx.Hex() >> hx.Chunk(2) >> hx.IntArray(
|
|
130
|
+
words = hx.Hex() >> hx.Chunk(2) >> hx.IntArray()
|
|
88
131
|
words("12345678")
|
|
89
132
|
# [4660, 22136]
|
|
90
133
|
|
|
@@ -111,30 +154,7 @@ conv("12345678")
|
|
|
111
154
|
# ['0x1234', '0x5678']
|
|
112
155
|
```
|
|
113
156
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
Use `convert` when you want an explicit source and target in one expression:
|
|
117
|
-
|
|
118
|
-
```python
|
|
119
|
-
hx.convert("de ad be ef", hx.Hex(sep=" "), hx.Bytes())
|
|
120
|
-
# b'\xde\xad\xbe\xef'
|
|
121
|
-
|
|
122
|
-
hx.convert("data", hx.Text(), hx.Hex(prefix=True))
|
|
123
|
-
# '0x64617461'
|
|
124
|
-
|
|
125
|
-
hx.convert("π", hx.Text(encoding="utf-8"), hx.Hex())
|
|
126
|
-
# 'cf80'
|
|
127
|
-
|
|
128
|
-
hx.convert("-_8", hx.Base64(urlsafe=True, padding=False), hx.Hex())
|
|
129
|
-
# 'fbff'
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
Hex strings may include common separators, so you do not need to manually strip
|
|
133
|
-
spaces, colons, dashes, or `0x` prefixes before converting.
|
|
134
|
-
|
|
135
|
-
## Common conversion patterns
|
|
136
|
-
|
|
137
|
-
Text, bytes, and hex:
|
|
157
|
+
More conversion patterns:
|
|
138
158
|
|
|
139
159
|
```python
|
|
140
160
|
hx.Text()("hello").bytes
|
|
@@ -143,54 +163,24 @@ hx.Text()("hello").bytes
|
|
|
143
163
|
hx.Hex()("68656c6c6f").text
|
|
144
164
|
# 'hello'
|
|
145
165
|
|
|
146
|
-
hx.BytesArray()([
|
|
147
|
-
# '
|
|
148
|
-
```
|
|
166
|
+
hx.BytesArray()([0x4F, 0x4B]).to(hx.Text())
|
|
167
|
+
# 'OK'
|
|
149
168
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
```python
|
|
153
|
-
hx.Int(width=2)(0x1234).hex
|
|
154
|
-
# '1234'
|
|
155
|
-
|
|
156
|
-
hx.Int(width=2, endian="little")(0x1234).hex
|
|
169
|
+
hx.Int(endian="little")(0x1234).hex
|
|
157
170
|
# '3412'
|
|
158
171
|
|
|
159
|
-
(hx.Hex() >> hx.Chunk(2) >> hx.IntArray(width=2))("12345678")
|
|
160
|
-
# [4660, 22136]
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
Base encodings:
|
|
164
|
-
|
|
165
|
-
```python
|
|
166
|
-
hx.Text()("data").to(hx.Base64())
|
|
167
|
-
# 'ZGF0YQ=='
|
|
168
|
-
|
|
169
172
|
hx.Text()("data").to(hx.Base32(padding=False))
|
|
170
173
|
# 'MRQXIYI'
|
|
171
174
|
|
|
172
|
-
hx.
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
Escaped strings, hexdumps, structs, and bits:
|
|
177
|
-
|
|
178
|
-
```python
|
|
179
|
-
hx.Escaped()(r"\xde\xad").hex
|
|
180
|
-
# 'dead'
|
|
181
|
-
|
|
182
|
-
dump = hx.Hex()("deadbeef").to(hx.Hexdump(width=2))
|
|
183
|
-
hx.Hexdump()(dump).hex
|
|
184
|
-
# 'deadbeef'
|
|
185
|
-
|
|
186
|
-
hx.Struct(">HH")((0x1234, 0x5678)).hex
|
|
187
|
-
# '12345678'
|
|
175
|
+
dump = hx.Text()("data").to(hx.Hexdump(width=2))
|
|
176
|
+
hx.Hexdump()(dump).text
|
|
177
|
+
# 'data'
|
|
188
178
|
|
|
189
179
|
hx.Hex()("12345678").to(hx.Struct(">HH"))
|
|
190
180
|
# (4660, 22136)
|
|
191
181
|
|
|
192
|
-
hx.Bits()(
|
|
193
|
-
# '
|
|
182
|
+
hx.Bits()("0100111101001011").text
|
|
183
|
+
# 'OK'
|
|
194
184
|
```
|
|
195
185
|
|
|
196
186
|
## Why explicit formats?
|
|
@@ -238,10 +228,10 @@ result.reason
|
|
|
238
228
|
`from_auto(..., explain=True)` returns the same explanation object:
|
|
239
229
|
|
|
240
230
|
```python
|
|
241
|
-
result = hx.from_auto("
|
|
231
|
+
result = hx.from_auto("0b0100111101001011", explain=True)
|
|
242
232
|
|
|
243
|
-
result.value.
|
|
244
|
-
# '
|
|
233
|
+
result.value.text
|
|
234
|
+
# 'OK'
|
|
245
235
|
```
|
|
246
236
|
|
|
247
237
|
## Design priorities
|
|
@@ -265,7 +255,7 @@ conv("deadbeef")
|
|
|
265
255
|
# 3735928559
|
|
266
256
|
```
|
|
267
257
|
|
|
268
|
-
Available format specs:
|
|
258
|
+
Available format specs all work in their simplest bare form:
|
|
269
259
|
|
|
270
260
|
- `Bytes()`
|
|
271
261
|
- `BytesArray()`
|
|
@@ -273,8 +263,8 @@ Available format specs:
|
|
|
273
263
|
- `Hex()`
|
|
274
264
|
- `HexArray()`
|
|
275
265
|
- `HexInt()` / `LargeHexNumber()`
|
|
276
|
-
- `Int()`
|
|
277
|
-
- `IntArray()`
|
|
266
|
+
- `Int()` / `DecimalInt()`
|
|
267
|
+
- `IntArray()` / `DecimalIntArray()`
|
|
278
268
|
- `Text()`
|
|
279
269
|
- `Binary()`
|
|
280
270
|
- `Base64()`
|
|
@@ -285,6 +275,20 @@ Available format specs:
|
|
|
285
275
|
- `Hexdump()`
|
|
286
276
|
- `Struct(fmt)`
|
|
287
277
|
- `Bits()`
|
|
278
|
+
- `Auto()`
|
|
279
|
+
|
|
280
|
+
Add options only when you need control over formatting or parsing:
|
|
281
|
+
|
|
282
|
+
- Display: `Hex(sep=" ", prefix=True, uppercase=True)`, `HexArray(width=2)`.
|
|
283
|
+
- Integer packing: `Int(width=4)`, `Int(endian="little")`, `IntArray(width=2)`.
|
|
284
|
+
- Text: `Text(encoding="utf-8", errors="replace")`.
|
|
285
|
+
- Base encodings: `Base64(urlsafe=True, padding=False)`, `Base32(padding=False)`.
|
|
286
|
+
- Binary/bits: `Binary(sep=" ", prefix=True, bit_order="lsb")`, `Bits(pad_side="right")`.
|
|
287
|
+
- Dumps/escapes/structs: `Hexdump(width=8)`, `Escaped(uppercase=True)`, `Struct(">HH")`.
|
|
288
|
+
|
|
289
|
+
Some options only matter in one direction. For example, `Hex(sep=" ")`
|
|
290
|
+
controls hex output formatting, while hex input already accepts common
|
|
291
|
+
separators such as spaces, colons, dashes, underscores, and `0x` prefixes.
|
|
288
292
|
|
|
289
293
|
## Transforms
|
|
290
294
|
|
|
@@ -292,7 +296,7 @@ Transforms are byte-to-byte steps that sit between input and output formats.
|
|
|
292
296
|
|
|
293
297
|
```python
|
|
294
298
|
hx.Hex() >> hx.Chunk(2) >> hx.HexArray()
|
|
295
|
-
hx.Hex() >> hx.Group(2) >> hx.IntArray(
|
|
299
|
+
hx.Hex() >> hx.Group(2) >> hx.IntArray()
|
|
296
300
|
hx.Hex() >> hx.Pad.left(width=8) >> hx.Hex()
|
|
297
301
|
hx.Hex() >> hx.Pad.right(block_size=8, byte=0xFF) >> hx.Hex()
|
|
298
302
|
hx.Hex() >> hx.Reverse() >> hx.Hex()
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "hexconv"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.5"
|
|
8
8
|
description = "Pythonic conversion toolkit for bytes, hex, integers, arrays, binary strings, base64, and text."
|
|
9
9
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hexconv
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.5
|
|
4
4
|
Summary: Pythonic conversion toolkit for bytes, hex, integers, arrays, binary strings, base64, and text.
|
|
5
5
|
Author: hexconv contributors
|
|
6
6
|
License-Expression: MIT
|
|
@@ -41,64 +41,99 @@ It is built around ergonomic one-liners and composable format objects.
|
|
|
41
41
|
pip install hexconv
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
##
|
|
44
|
+
## Simple usage
|
|
45
45
|
|
|
46
|
-
Use
|
|
46
|
+
Most conversions are one-liners. Use `from_auto` when you want a quick
|
|
47
|
+
best-effort parse, or pick an explicit helper when the input is ambiguous.
|
|
47
48
|
|
|
48
49
|
```python
|
|
49
50
|
import hexconv as hx
|
|
50
51
|
|
|
51
|
-
hx.
|
|
52
|
-
#
|
|
52
|
+
hx.from_auto("0x64617461").text
|
|
53
|
+
# 'data'
|
|
53
54
|
|
|
54
|
-
hx.
|
|
55
|
-
#
|
|
55
|
+
hx.from_bytes_array([0xde, 0xad, 0xbe, 0xef]).int
|
|
56
|
+
# 3735928559
|
|
56
57
|
|
|
57
|
-
hx.
|
|
58
|
-
# '
|
|
58
|
+
hx.from_text("data").hex
|
|
59
|
+
# '64617461'
|
|
60
|
+
```
|
|
59
61
|
|
|
60
|
-
|
|
61
|
-
# 'deadbeef'
|
|
62
|
+
## Fast compose
|
|
62
63
|
|
|
63
|
-
|
|
64
|
-
|
|
64
|
+
Create your own converters by snapping together
|
|
65
|
+
`source format >> optional transforms >> target format`.
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
```python
|
|
68
|
+
to_bytes = hx.Hex() >> hx.Bytes()
|
|
69
|
+
to_bytes("68 69")
|
|
70
|
+
# b'hi'
|
|
68
71
|
|
|
69
|
-
hx.
|
|
70
|
-
|
|
72
|
+
spaced_hex = hx.Bytes() >> hx.Hex(sep=" ")
|
|
73
|
+
spaced_hex(b"data")
|
|
74
|
+
# '64 61 74 61'
|
|
75
|
+
|
|
76
|
+
words = hx.Hex() >> hx.Chunk(2) >> hx.IntArray()
|
|
77
|
+
words("12 34 56 78")
|
|
78
|
+
# [4660, 22136]
|
|
79
|
+
|
|
80
|
+
pack_to_hex = hx.Struct(">HH") >> hx.Hex()
|
|
81
|
+
pack_to_hex((0x1234, 0x5678))
|
|
82
|
+
# '12345678'
|
|
71
83
|
```
|
|
72
84
|
|
|
73
|
-
|
|
85
|
+
## Configure when needed
|
|
86
|
+
|
|
87
|
+
Formats work bare by default. Add arguments only for the conversion that needs
|
|
88
|
+
them:
|
|
74
89
|
|
|
75
90
|
```python
|
|
76
|
-
hx.
|
|
91
|
+
hx.convert("de ad be ef", hx.Hex(), hx.Bytes())
|
|
77
92
|
# b'\xde\xad\xbe\xef'
|
|
78
93
|
|
|
79
|
-
hx.
|
|
80
|
-
# '
|
|
94
|
+
hx.convert(b"\xde\xad\xbe\xef", hx.Bytes(), hx.Hex(sep=" ", prefix=True, uppercase=True))
|
|
95
|
+
# '0xDE AD BE EF'
|
|
96
|
+
|
|
97
|
+
hx.convert("π", hx.Text(encoding="utf-8"), hx.Hex())
|
|
98
|
+
# 'cf80'
|
|
81
99
|
|
|
82
|
-
hx.
|
|
83
|
-
# '
|
|
100
|
+
hx.from_int(0x12345678, endian="little").hex
|
|
101
|
+
# '78563412'
|
|
102
|
+
|
|
103
|
+
hx.convert("ZGF0YQ", hx.Base64(padding=False), hx.Text())
|
|
104
|
+
# 'data'
|
|
105
|
+
|
|
106
|
+
hx.from_binary("00010110 10010110", bit_order="lsb").text
|
|
107
|
+
# 'hi'
|
|
84
108
|
```
|
|
85
109
|
|
|
86
|
-
|
|
110
|
+
Hex strings may include common separators, so you do not need to manually strip
|
|
111
|
+
spaces, colons, dashes, or `0x` prefixes before converting. `Hex(sep=" ")` is
|
|
112
|
+
how you emit space-separated hex.
|
|
113
|
+
|
|
114
|
+
## Full pipeline guide
|
|
87
115
|
|
|
88
116
|
`hexconv` is built around small format objects. A format can parse directly:
|
|
89
117
|
|
|
90
118
|
```python
|
|
91
|
-
hx.Hex()("
|
|
119
|
+
hx.Hex()("de ad be ef").bytes
|
|
92
120
|
# b'\xde\xad\xbe\xef'
|
|
93
121
|
|
|
94
122
|
hx.Text()("data").hex
|
|
95
123
|
# '64617461'
|
|
96
124
|
|
|
97
|
-
hx.Int(
|
|
125
|
+
hx.Int(endian="little")(0x12345678).hex
|
|
98
126
|
# '78563412'
|
|
127
|
+
|
|
128
|
+
pack_words = hx.Struct(">HH")
|
|
129
|
+
pack_words((0x1234, 0x5678)).hex
|
|
130
|
+
# '12345678'
|
|
131
|
+
|
|
132
|
+
hx.Hex()("12345678").to(pack_words)
|
|
133
|
+
# (4660, 22136)
|
|
99
134
|
```
|
|
100
135
|
|
|
101
|
-
Formats compose with
|
|
136
|
+
Formats compose with `>>`, so reusable converters are normal Python objects:
|
|
102
137
|
|
|
103
138
|
```python
|
|
104
139
|
to_text = hx.HexArray() >> hx.Text()
|
|
@@ -108,12 +143,20 @@ to_text([0x48, 0x65, 0x6C, 0x6C, 0x6F])
|
|
|
108
143
|
to_hex = hx.Text() >> hx.Hex(prefix=True)
|
|
109
144
|
to_hex("data")
|
|
110
145
|
# '0x64617461'
|
|
146
|
+
|
|
147
|
+
pack_to_hex = hx.Struct(">HH") >> hx.Hex()
|
|
148
|
+
pack_to_hex((0x1234, 0x5678))
|
|
149
|
+
# '12345678'
|
|
150
|
+
|
|
151
|
+
unpack_from_hex = hx.Hex() >> hx.Struct(">HH")
|
|
152
|
+
unpack_from_hex("12345678")
|
|
153
|
+
# (4660, 22136)
|
|
111
154
|
```
|
|
112
155
|
|
|
113
156
|
Transforms sit between formats when data needs shaping:
|
|
114
157
|
|
|
115
158
|
```python
|
|
116
|
-
words = hx.Hex() >> hx.Chunk(2) >> hx.IntArray(
|
|
159
|
+
words = hx.Hex() >> hx.Chunk(2) >> hx.IntArray()
|
|
117
160
|
words("12345678")
|
|
118
161
|
# [4660, 22136]
|
|
119
162
|
|
|
@@ -140,30 +183,7 @@ conv("12345678")
|
|
|
140
183
|
# ['0x1234', '0x5678']
|
|
141
184
|
```
|
|
142
185
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
Use `convert` when you want an explicit source and target in one expression:
|
|
146
|
-
|
|
147
|
-
```python
|
|
148
|
-
hx.convert("de ad be ef", hx.Hex(sep=" "), hx.Bytes())
|
|
149
|
-
# b'\xde\xad\xbe\xef'
|
|
150
|
-
|
|
151
|
-
hx.convert("data", hx.Text(), hx.Hex(prefix=True))
|
|
152
|
-
# '0x64617461'
|
|
153
|
-
|
|
154
|
-
hx.convert("π", hx.Text(encoding="utf-8"), hx.Hex())
|
|
155
|
-
# 'cf80'
|
|
156
|
-
|
|
157
|
-
hx.convert("-_8", hx.Base64(urlsafe=True, padding=False), hx.Hex())
|
|
158
|
-
# 'fbff'
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
Hex strings may include common separators, so you do not need to manually strip
|
|
162
|
-
spaces, colons, dashes, or `0x` prefixes before converting.
|
|
163
|
-
|
|
164
|
-
## Common conversion patterns
|
|
165
|
-
|
|
166
|
-
Text, bytes, and hex:
|
|
186
|
+
More conversion patterns:
|
|
167
187
|
|
|
168
188
|
```python
|
|
169
189
|
hx.Text()("hello").bytes
|
|
@@ -172,54 +192,24 @@ hx.Text()("hello").bytes
|
|
|
172
192
|
hx.Hex()("68656c6c6f").text
|
|
173
193
|
# 'hello'
|
|
174
194
|
|
|
175
|
-
hx.BytesArray()([
|
|
176
|
-
# '
|
|
177
|
-
```
|
|
195
|
+
hx.BytesArray()([0x4F, 0x4B]).to(hx.Text())
|
|
196
|
+
# 'OK'
|
|
178
197
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
```python
|
|
182
|
-
hx.Int(width=2)(0x1234).hex
|
|
183
|
-
# '1234'
|
|
184
|
-
|
|
185
|
-
hx.Int(width=2, endian="little")(0x1234).hex
|
|
198
|
+
hx.Int(endian="little")(0x1234).hex
|
|
186
199
|
# '3412'
|
|
187
200
|
|
|
188
|
-
(hx.Hex() >> hx.Chunk(2) >> hx.IntArray(width=2))("12345678")
|
|
189
|
-
# [4660, 22136]
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
Base encodings:
|
|
193
|
-
|
|
194
|
-
```python
|
|
195
|
-
hx.Text()("data").to(hx.Base64())
|
|
196
|
-
# 'ZGF0YQ=='
|
|
197
|
-
|
|
198
201
|
hx.Text()("data").to(hx.Base32(padding=False))
|
|
199
202
|
# 'MRQXIYI'
|
|
200
203
|
|
|
201
|
-
hx.
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
Escaped strings, hexdumps, structs, and bits:
|
|
206
|
-
|
|
207
|
-
```python
|
|
208
|
-
hx.Escaped()(r"\xde\xad").hex
|
|
209
|
-
# 'dead'
|
|
210
|
-
|
|
211
|
-
dump = hx.Hex()("deadbeef").to(hx.Hexdump(width=2))
|
|
212
|
-
hx.Hexdump()(dump).hex
|
|
213
|
-
# 'deadbeef'
|
|
214
|
-
|
|
215
|
-
hx.Struct(">HH")((0x1234, 0x5678)).hex
|
|
216
|
-
# '12345678'
|
|
204
|
+
dump = hx.Text()("data").to(hx.Hexdump(width=2))
|
|
205
|
+
hx.Hexdump()(dump).text
|
|
206
|
+
# 'data'
|
|
217
207
|
|
|
218
208
|
hx.Hex()("12345678").to(hx.Struct(">HH"))
|
|
219
209
|
# (4660, 22136)
|
|
220
210
|
|
|
221
|
-
hx.Bits()(
|
|
222
|
-
# '
|
|
211
|
+
hx.Bits()("0100111101001011").text
|
|
212
|
+
# 'OK'
|
|
223
213
|
```
|
|
224
214
|
|
|
225
215
|
## Why explicit formats?
|
|
@@ -267,10 +257,10 @@ result.reason
|
|
|
267
257
|
`from_auto(..., explain=True)` returns the same explanation object:
|
|
268
258
|
|
|
269
259
|
```python
|
|
270
|
-
result = hx.from_auto("
|
|
260
|
+
result = hx.from_auto("0b0100111101001011", explain=True)
|
|
271
261
|
|
|
272
|
-
result.value.
|
|
273
|
-
# '
|
|
262
|
+
result.value.text
|
|
263
|
+
# 'OK'
|
|
274
264
|
```
|
|
275
265
|
|
|
276
266
|
## Design priorities
|
|
@@ -294,7 +284,7 @@ conv("deadbeef")
|
|
|
294
284
|
# 3735928559
|
|
295
285
|
```
|
|
296
286
|
|
|
297
|
-
Available format specs:
|
|
287
|
+
Available format specs all work in their simplest bare form:
|
|
298
288
|
|
|
299
289
|
- `Bytes()`
|
|
300
290
|
- `BytesArray()`
|
|
@@ -302,8 +292,8 @@ Available format specs:
|
|
|
302
292
|
- `Hex()`
|
|
303
293
|
- `HexArray()`
|
|
304
294
|
- `HexInt()` / `LargeHexNumber()`
|
|
305
|
-
- `Int()`
|
|
306
|
-
- `IntArray()`
|
|
295
|
+
- `Int()` / `DecimalInt()`
|
|
296
|
+
- `IntArray()` / `DecimalIntArray()`
|
|
307
297
|
- `Text()`
|
|
308
298
|
- `Binary()`
|
|
309
299
|
- `Base64()`
|
|
@@ -314,6 +304,20 @@ Available format specs:
|
|
|
314
304
|
- `Hexdump()`
|
|
315
305
|
- `Struct(fmt)`
|
|
316
306
|
- `Bits()`
|
|
307
|
+
- `Auto()`
|
|
308
|
+
|
|
309
|
+
Add options only when you need control over formatting or parsing:
|
|
310
|
+
|
|
311
|
+
- Display: `Hex(sep=" ", prefix=True, uppercase=True)`, `HexArray(width=2)`.
|
|
312
|
+
- Integer packing: `Int(width=4)`, `Int(endian="little")`, `IntArray(width=2)`.
|
|
313
|
+
- Text: `Text(encoding="utf-8", errors="replace")`.
|
|
314
|
+
- Base encodings: `Base64(urlsafe=True, padding=False)`, `Base32(padding=False)`.
|
|
315
|
+
- Binary/bits: `Binary(sep=" ", prefix=True, bit_order="lsb")`, `Bits(pad_side="right")`.
|
|
316
|
+
- Dumps/escapes/structs: `Hexdump(width=8)`, `Escaped(uppercase=True)`, `Struct(">HH")`.
|
|
317
|
+
|
|
318
|
+
Some options only matter in one direction. For example, `Hex(sep=" ")`
|
|
319
|
+
controls hex output formatting, while hex input already accepts common
|
|
320
|
+
separators such as spaces, colons, dashes, underscores, and `0x` prefixes.
|
|
317
321
|
|
|
318
322
|
## Transforms
|
|
319
323
|
|
|
@@ -321,7 +325,7 @@ Transforms are byte-to-byte steps that sit between input and output formats.
|
|
|
321
325
|
|
|
322
326
|
```python
|
|
323
327
|
hx.Hex() >> hx.Chunk(2) >> hx.HexArray()
|
|
324
|
-
hx.Hex() >> hx.Group(2) >> hx.IntArray(
|
|
328
|
+
hx.Hex() >> hx.Group(2) >> hx.IntArray()
|
|
325
329
|
hx.Hex() >> hx.Pad.left(width=8) >> hx.Hex()
|
|
326
330
|
hx.Hex() >> hx.Pad.right(block_size=8, byte=0xFF) >> hx.Hex()
|
|
327
331
|
hx.Hex() >> hx.Reverse() >> hx.Hex()
|
|
@@ -45,10 +45,56 @@ def test_converter_class_matches_proposed_usage():
|
|
|
45
45
|
|
|
46
46
|
def test_convert_one_shot():
|
|
47
47
|
assert hx.convert("data", from_=hx.Text, to=hx.HexString) == "64617461"
|
|
48
|
-
assert hx.convert("de ad be ef", hx.Hex(
|
|
48
|
+
assert hx.convert("de ad be ef", hx.Hex(), hx.Bytes()) == b"\xde\xad\xbe\xef"
|
|
49
|
+
assert hx.convert(b"\xde\xad\xbe\xef", hx.Bytes(), hx.Hex(sep=" ")) == "de ad be ef"
|
|
49
50
|
assert hx.convert("data", hx.Text(), hx.Hex(prefix=True)) == "0x64617461"
|
|
50
51
|
|
|
51
52
|
|
|
53
|
+
def test_documented_format_options_quick_tour():
|
|
54
|
+
assert hx.from_hex("de ad:be-ef").bytes == b"\xde\xad\xbe\xef"
|
|
55
|
+
assert hx.from_bytes(b"\xde\xad\xbe\xef").to(hx.Hex(sep=":", uppercase=True)) == "DE:AD:BE:EF"
|
|
56
|
+
assert hx.from_bytes_array([0xDE, 0xAD, 0xBE, 0xEF]).to(
|
|
57
|
+
hx.HexArray(width=2, prefix=True, uppercase=True)
|
|
58
|
+
) == ["0xDEAD", "0xBEEF"]
|
|
59
|
+
assert hx.from_text("π", encoding="utf-8").to(hx.Hex(prefix=True)) == "0xcf80"
|
|
60
|
+
assert hx.from_int(0x12345678, endian="little").hex == "78563412"
|
|
61
|
+
assert hx.from_int_array([0x1234, 0x5678], width=2).to(hx.HexArray(width=2)) == [
|
|
62
|
+
"1234",
|
|
63
|
+
"5678",
|
|
64
|
+
]
|
|
65
|
+
assert hx.from_binary("01100100 01100001 01110100 01100001").text == "data"
|
|
66
|
+
assert hx.from_base64("-_8", urlsafe=True, padding=False).hex == "fbff"
|
|
67
|
+
assert hx.from_base32("MRQXIYI", padding=False).text == "data"
|
|
68
|
+
assert hx.from_escaped(r"\xDE\xAD").hex == "dead"
|
|
69
|
+
assert hx.from_struct((0x1234, 0x5678), fmt=">HH").hex == "12345678"
|
|
70
|
+
assert hx.from_bits("101", pad_side="right").hex == "a0"
|
|
71
|
+
|
|
72
|
+
assert hx.convert("de ad be ef", hx.Hex(), hx.Bytes()) == b"\xde\xad\xbe\xef"
|
|
73
|
+
assert (
|
|
74
|
+
hx.convert(
|
|
75
|
+
b"\xde\xad\xbe\xef",
|
|
76
|
+
hx.Bytes(),
|
|
77
|
+
hx.Hex(sep=" ", prefix=True, uppercase=True),
|
|
78
|
+
)
|
|
79
|
+
== "0xDE AD BE EF"
|
|
80
|
+
)
|
|
81
|
+
assert hx.convert(["0xDEAD", "0xBEEF"], hx.HexArray(width=2), hx.IntArray(width=2)) == [
|
|
82
|
+
57005,
|
|
83
|
+
48879,
|
|
84
|
+
]
|
|
85
|
+
assert hx.convert("78563412", hx.Hex(), hx.Int(endian="little")) == 305419896
|
|
86
|
+
assert hx.convert("0b10100000", hx.Binary(bit_order="lsb"), hx.Hex()) == "05"
|
|
87
|
+
assert hx.from_text("data").to(hx.Base64(urlsafe=True, padding=False)) == "ZGF0YQ"
|
|
88
|
+
assert hx.from_text("data").to(hx.Base85()) == "WMOn+"
|
|
89
|
+
assert hx.from_text("data").to(hx.Ascii85(adobe=True)) == "<~A79Rg~>"
|
|
90
|
+
assert hx.from_hex("deadbeef").to(hx.Hexdump(width=2, offset=False, ascii=False)) == "de ad\nbe ef"
|
|
91
|
+
assert hx.from_hex("dead").to(hx.Escaped(uppercase=True)) == r"\xDE\xAD"
|
|
92
|
+
assert hx.from_hex("0506").to(hx.Binary(sep=" ", prefix=True, bit_order="lsb")) == (
|
|
93
|
+
"0b10100000 0b01100000"
|
|
94
|
+
)
|
|
95
|
+
assert hx.from_hex("05").to(hx.Bits(bit_order="lsb")) == [1, 0, 1, 0, 0, 0, 0, 0]
|
|
96
|
+
|
|
97
|
+
|
|
52
98
|
def test_convert_rejects_mixed_positional_and_keyword_formats():
|
|
53
99
|
with pytest.raises(hx.HexConvError, match="from_"):
|
|
54
100
|
hx.convert("data", hx.Text(), from_=hx.Text(), to=hx.Hex())
|
|
@@ -114,10 +160,10 @@ def test_constructable_hex_and_text_specs():
|
|
|
114
160
|
|
|
115
161
|
|
|
116
162
|
def test_pipeline_builder_and_shift_composition():
|
|
117
|
-
conv = hx.pipeline().from_(hx.Hex(
|
|
163
|
+
conv = hx.pipeline().from_(hx.Hex()).chunk(2).to(hx.IntArray())
|
|
118
164
|
assert conv("12 34 56 78") == [0x1234, 0x5678]
|
|
119
165
|
|
|
120
|
-
shift_conv = hx.Hex(
|
|
166
|
+
shift_conv = hx.Hex() >> hx.Chunk(2) >> hx.HexArray()
|
|
121
167
|
assert shift_conv("12 34 56 78") == ["1234", "5678"]
|
|
122
168
|
|
|
123
169
|
|
|
@@ -160,6 +206,9 @@ def test_struct_format_pack_and_unpack():
|
|
|
160
206
|
assert packed.hex == "12345678"
|
|
161
207
|
assert packed.to(hx.Struct(">HH")) == (0x1234, 0x5678)
|
|
162
208
|
assert hx.convert((0x1234, 0x5678), from_=hx.Struct(">HH"), to=hx.Hex()) == "12345678"
|
|
209
|
+
assert hx.Struct(">HH")((0x1234, 0x5678)).hex == "12345678"
|
|
210
|
+
assert (hx.Struct(">HH") >> hx.Hex())((0x1234, 0x5678)) == "12345678"
|
|
211
|
+
assert (hx.Hex() >> hx.Struct(">HH"))("12345678") == (0x1234, 0x5678)
|
|
163
212
|
|
|
164
213
|
|
|
165
214
|
def test_bit_array_and_lsb_bit_order():
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|