hexconv 0.2.4__tar.gz → 0.2.6__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hexconv
3
- Version: 0.2.4
3
+ Version: 0.2.6
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,83 +41,96 @@ It is built around ergonomic one-liners and composable format objects.
41
41
  pip install hexconv
42
42
  ```
43
43
 
44
- ## Fast compose
44
+ ## Simple usage
45
45
 
46
- The intended interface is small pieces snapped together:
47
- `source format >> optional transforms >> target format`.
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.
48
48
 
49
49
  ```python
50
50
  import hexconv as hx
51
51
 
52
- to_bytes = hx.Hex() >> hx.Bytes()
53
- to_bytes("de ad be ef")
54
- # b'\xde\xad\xbe\xef'
55
-
56
- spaced_hex = hx.Bytes() >> hx.Hex(sep=" ")
57
- spaced_hex(b"\xde\xad\xbe\xef")
58
- # 'de ad be ef'
52
+ hx.from_auto("0x64617461").text
53
+ # 'data'
59
54
 
60
- words = hx.Hex(sep=" ") >> hx.Chunk(2) >> hx.IntArray(width=2)
61
- words("12 34 56 78")
62
- # [4660, 22136]
55
+ hx.from_bytes_array([0xde, 0xad, 0xbe, 0xef]).int
56
+ # 3735928559
63
57
 
64
- text_to_urlsafe = hx.Text() >> hx.Base64(urlsafe=True, padding=False)
65
- text_to_urlsafe("data")
66
- # 'ZGF0YQ'
58
+ hx.from_text("data").hex
59
+ # '64617461'
67
60
  ```
68
61
 
69
- Hex input accepts common separators, so spaced or copied hex usually does not
70
- need manual cleanup before conversion. `Hex(sep=" ")` is also how you emit
71
- space-separated hex.
62
+ The bare `.hex`, `.text`, and `.bytes` properties are shortcuts for zero-argument
63
+ `to_*` methods. Call the method form when you need options:
72
64
 
73
- ## Quick tour
65
+ ```python
66
+ value = hx.from_hex("deadbeef")
74
67
 
75
- Use direct helpers when you want one obvious conversion across many
76
- representations:
68
+ value.to_hex()
69
+ # 'deadbeef' (same as value.hex)
77
70
 
78
- ```python
79
- hx.from_hex("de ad be ef").bytes
71
+ value.to_hex(sep=" ", uppercase=True)
72
+ # 'DE AD BE EF'
73
+
74
+ value.to_bytes()
80
75
  # b'\xde\xad\xbe\xef'
81
76
 
82
- hx.from_text("data").to_hex_array(prefix=True)
83
- # ['0x64', '0x61', '0x74', '0x61']
77
+ hx.from_hex("68656c6c6f").to_text()
78
+ # 'hello'
79
+ ```
84
80
 
85
- hx.from_int(0xdeadbeef).bytes
86
- # b'\xde\xad\xbe\xef'
81
+ ## Fast compose
87
82
 
88
- hx.from_int_array([0x1234, 0x5678], width=2).to_hex_array(width=2)
89
- # ['1234', '5678']
83
+ Create your own converters by snapping together
84
+ `source format >> optional transforms >> target format`.
90
85
 
91
- hx.from_binary("01100100 01100001 01110100 01100001").text
92
- # 'data'
86
+ ```python
87
+ to_bytes = hx.Hex() >> hx.Bytes()
88
+ to_bytes("68 69")
89
+ # b'hi'
93
90
 
94
- hx.from_base64("ZGF0YQ==").text
95
- # 'data'
91
+ spaced_hex = hx.Bytes() >> hx.Hex(sep=" ")
92
+ spaced_hex(b"data")
93
+ # '64 61 74 61'
96
94
 
97
- hx.from_escaped(r"\xde\xad").hex
98
- # 'dead'
95
+ words = hx.Hex() >> hx.Chunk(2) >> hx.IntArray()
96
+ words("12 34 56 78")
97
+ # [4660, 22136]
99
98
 
100
- hx.from_struct((0x1234, 0x5678), fmt=">HH").hex
99
+ pack_to_hex = hx.Struct(">HH") >> hx.Hex()
100
+ pack_to_hex((0x1234, 0x5678))
101
101
  # '12345678'
102
-
103
- hx.from_bits("101", pad=True).hex
104
- # '05'
105
102
  ```
106
103
 
107
- Use `from_auto` when you want a quick best-effort parse:
104
+ ## Configure when needed
105
+
106
+ Formats work bare by default. Add arguments only for the conversion that needs
107
+ them:
108
108
 
109
109
  ```python
110
- hx.from_auto("0xdeadbeef").bytes
110
+ hx.convert("de ad be ef", hx.Hex(), hx.Bytes())
111
111
  # b'\xde\xad\xbe\xef'
112
112
 
113
- hx.from_auto(b"\xde\xad").hex
114
- # 'dead'
113
+ hx.convert(b"\xde\xad\xbe\xef", hx.Bytes(), hx.Hex(sep=" ", prefix=True, uppercase=True))
114
+ # '0xDE AD BE EF'
115
+
116
+ hx.convert("π", hx.Text(encoding="utf-8"), hx.Hex())
117
+ # 'cf80'
115
118
 
116
- hx.from_auto([0xde, 0xad, 0xbe, 0xef]).to(hx.Hex(prefix=True))
117
- # '0xdeadbeef'
119
+ hx.from_int(0x12345678, endian="little").hex
120
+ # '78563412'
121
+
122
+ hx.convert("ZGF0YQ", hx.Base64(padding=False), hx.Text())
123
+ # 'data'
124
+
125
+ hx.from_binary("00010110 10010110", bit_order="lsb").text
126
+ # 'hi'
118
127
  ```
119
128
 
120
- ## Composable interface
129
+ Hex strings may include common separators, so you do not need to manually strip
130
+ spaces, colons, dashes, or `0x` prefixes before converting. `Hex(sep=" ")` is
131
+ how you emit space-separated hex.
132
+
133
+ ## Full pipeline guide
121
134
 
122
135
  `hexconv` is built around small format objects. A format can parse directly:
123
136
 
@@ -128,8 +141,15 @@ hx.Hex()("de ad be ef").bytes
128
141
  hx.Text()("data").hex
129
142
  # '64617461'
130
143
 
131
- hx.Int(width=4, endian="little")(0x12345678).hex
144
+ hx.Int(endian="little")(0x12345678).hex
132
145
  # '78563412'
146
+
147
+ pack_words = hx.Struct(">HH")
148
+ pack_words((0x1234, 0x5678)).hex
149
+ # '12345678'
150
+
151
+ hx.Hex()("12345678").to(pack_words)
152
+ # (4660, 22136)
133
153
  ```
134
154
 
135
155
  Formats compose with `>>`, so reusable converters are normal Python objects:
@@ -142,12 +162,20 @@ to_text([0x48, 0x65, 0x6C, 0x6C, 0x6F])
142
162
  to_hex = hx.Text() >> hx.Hex(prefix=True)
143
163
  to_hex("data")
144
164
  # '0x64617461'
165
+
166
+ pack_to_hex = hx.Struct(">HH") >> hx.Hex()
167
+ pack_to_hex((0x1234, 0x5678))
168
+ # '12345678'
169
+
170
+ unpack_from_hex = hx.Hex() >> hx.Struct(">HH")
171
+ unpack_from_hex("12345678")
172
+ # (4660, 22136)
145
173
  ```
146
174
 
147
175
  Transforms sit between formats when data needs shaping:
148
176
 
149
177
  ```python
150
- words = hx.Hex() >> hx.Chunk(2) >> hx.IntArray(width=2)
178
+ words = hx.Hex() >> hx.Chunk(2) >> hx.IntArray()
151
179
  words("12345678")
152
180
  # [4660, 22136]
153
181
 
@@ -174,89 +202,27 @@ conv("12345678")
174
202
  # ['0x1234', '0x5678']
175
203
  ```
176
204
 
177
- ## Configurable one-shot conversions
178
-
179
- Use `convert` when you want an explicit source and target in one expression:
180
-
181
- ```python
182
- hx.convert("de ad be ef", hx.Hex(sep=" "), hx.Bytes())
183
- # b'\xde\xad\xbe\xef'
184
-
185
- hx.convert(b"\xde\xad\xbe\xef", hx.Bytes(), hx.Hex(sep=" "))
186
- # 'de ad be ef'
187
-
188
- hx.convert("data", hx.Text(), hx.Hex(prefix=True))
189
- # '0x64617461'
190
-
191
- hx.convert("π", hx.Text(encoding="utf-8"), hx.Hex())
192
- # 'cf80'
193
-
194
- hx.convert("-_8", hx.Base64(urlsafe=True, padding=False), hx.Hex())
195
- # 'fbff'
196
- ```
197
-
198
- Hex strings may include common separators, so you do not need to manually strip
199
- spaces, colons, dashes, or `0x` prefixes before converting.
200
-
201
- ## Common conversion patterns
202
-
203
- Text, bytes, and hex:
204
-
205
- ```python
206
- hx.Text()("hello").bytes
207
- # b'hello'
208
-
209
- hx.Hex()("68656c6c6f").text
210
- # 'hello'
211
-
212
- hx.BytesArray()([0x68, 0x69]).to(hx.Text())
213
- # 'hi'
214
- ```
215
-
216
- Integer packing:
205
+ More conversion patterns:
217
206
 
218
207
  ```python
219
- hx.Int(width=2)(0x1234).hex
220
- # '1234'
208
+ hx.BytesArray()([0x4F, 0x4B]).to(hx.Text())
209
+ # 'OK'
221
210
 
222
- hx.Int(width=2, endian="little")(0x1234).hex
211
+ hx.Int(endian="little")(0x1234).hex
223
212
  # '3412'
224
213
 
225
- (hx.Hex() >> hx.Chunk(2) >> hx.IntArray(width=2))("12345678")
226
- # [4660, 22136]
227
- ```
228
-
229
- Base encodings:
230
-
231
- ```python
232
- hx.Text()("data").to(hx.Base64())
233
- # 'ZGF0YQ=='
234
-
235
214
  hx.Text()("data").to(hx.Base32(padding=False))
236
215
  # 'MRQXIYI'
237
216
 
238
- hx.Base64(urlsafe=True, padding=False)("-_8").hex
239
- # 'fbff'
240
- ```
241
-
242
- Escaped strings, hexdumps, structs, and bits:
243
-
244
- ```python
245
- hx.Escaped()(r"\xde\xad").hex
246
- # 'dead'
247
-
248
- dump = hx.Hex()("deadbeef").to(hx.Hexdump(width=2))
249
- hx.Hexdump()(dump).hex
250
- # 'deadbeef'
251
-
252
- hx.Struct(">HH")((0x1234, 0x5678)).hex
253
- # '12345678'
217
+ dump = hx.Text()("data").to(hx.Hexdump(width=2))
218
+ hx.Hexdump()(dump).text
219
+ # 'data'
254
220
 
255
221
  hx.Hex()("12345678").to(hx.Struct(">HH"))
256
222
  # (4660, 22136)
257
223
 
258
- hx.Bits()([1, 0, 1]).hex
259
- # '05'
224
+ hx.Bits()("0100111101001011").text
225
+ # 'OK'
260
226
  ```
261
227
 
262
228
  ## Why explicit formats?
@@ -304,10 +270,10 @@ result.reason
304
270
  `from_auto(..., explain=True)` returns the same explanation object:
305
271
 
306
272
  ```python
307
- result = hx.from_auto("0b101", explain=True)
273
+ result = hx.from_auto("0b0100111101001011", explain=True)
308
274
 
309
- result.value.hex
310
- # '05'
275
+ result.value.text
276
+ # 'OK'
311
277
  ```
312
278
 
313
279
  ## Design priorities
@@ -331,7 +297,7 @@ conv("deadbeef")
331
297
  # 3735928559
332
298
  ```
333
299
 
334
- Available format specs:
300
+ Available format specs all work in their simplest bare form:
335
301
 
336
302
  - `Bytes()`
337
303
  - `BytesArray()`
@@ -339,8 +305,8 @@ Available format specs:
339
305
  - `Hex()`
340
306
  - `HexArray()`
341
307
  - `HexInt()` / `LargeHexNumber()`
342
- - `Int()`
343
- - `IntArray()`
308
+ - `Int()` / `DecimalInt()`
309
+ - `IntArray()` / `DecimalIntArray()`
344
310
  - `Text()`
345
311
  - `Binary()`
346
312
  - `Base64()`
@@ -351,6 +317,20 @@ Available format specs:
351
317
  - `Hexdump()`
352
318
  - `Struct(fmt)`
353
319
  - `Bits()`
320
+ - `Auto()`
321
+
322
+ Add options only when you need control over formatting or parsing:
323
+
324
+ - Display: `Hex(sep=" ", prefix=True, uppercase=True)`, `HexArray(width=2)`.
325
+ - Integer packing: `Int(width=4)`, `Int(endian="little")`, `IntArray(width=2)`.
326
+ - Text: `Text(encoding="utf-8", errors="replace")`.
327
+ - Base encodings: `Base64(urlsafe=True, padding=False)`, `Base32(padding=False)`.
328
+ - Binary/bits: `Binary(sep=" ", prefix=True, bit_order="lsb")`, `Bits(pad_side="right")`.
329
+ - Dumps/escapes/structs: `Hexdump(width=8)`, `Escaped(uppercase=True)`, `Struct(">HH")`.
330
+
331
+ Some options only matter in one direction. For example, `Hex(sep=" ")`
332
+ controls hex output formatting, while hex input already accepts common
333
+ separators such as spaces, colons, dashes, underscores, and `0x` prefixes.
354
334
 
355
335
  ## Transforms
356
336
 
@@ -358,7 +338,7 @@ Transforms are byte-to-byte steps that sit between input and output formats.
358
338
 
359
339
  ```python
360
340
  hx.Hex() >> hx.Chunk(2) >> hx.HexArray()
361
- hx.Hex() >> hx.Group(2) >> hx.IntArray(width=2)
341
+ hx.Hex() >> hx.Group(2) >> hx.IntArray()
362
342
  hx.Hex() >> hx.Pad.left(width=8) >> hx.Hex()
363
343
  hx.Hex() >> hx.Pad.right(block_size=8, byte=0xFF) >> hx.Hex()
364
344
  hx.Hex() >> hx.Reverse() >> hx.Hex()
@@ -12,83 +12,96 @@ It is built around ergonomic one-liners and composable format objects.
12
12
  pip install hexconv
13
13
  ```
14
14
 
15
- ## Fast compose
15
+ ## Simple usage
16
16
 
17
- The intended interface is small pieces snapped together:
18
- `source format >> optional transforms >> target format`.
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.
19
19
 
20
20
  ```python
21
21
  import hexconv as hx
22
22
 
23
- to_bytes = hx.Hex() >> hx.Bytes()
24
- to_bytes("de ad be ef")
25
- # b'\xde\xad\xbe\xef'
26
-
27
- spaced_hex = hx.Bytes() >> hx.Hex(sep=" ")
28
- spaced_hex(b"\xde\xad\xbe\xef")
29
- # 'de ad be ef'
23
+ hx.from_auto("0x64617461").text
24
+ # 'data'
30
25
 
31
- words = hx.Hex(sep=" ") >> hx.Chunk(2) >> hx.IntArray(width=2)
32
- words("12 34 56 78")
33
- # [4660, 22136]
26
+ hx.from_bytes_array([0xde, 0xad, 0xbe, 0xef]).int
27
+ # 3735928559
34
28
 
35
- text_to_urlsafe = hx.Text() >> hx.Base64(urlsafe=True, padding=False)
36
- text_to_urlsafe("data")
37
- # 'ZGF0YQ'
29
+ hx.from_text("data").hex
30
+ # '64617461'
38
31
  ```
39
32
 
40
- Hex input accepts common separators, so spaced or copied hex usually does not
41
- need manual cleanup before conversion. `Hex(sep=" ")` is also how you emit
42
- space-separated hex.
33
+ The bare `.hex`, `.text`, and `.bytes` properties are shortcuts for zero-argument
34
+ `to_*` methods. Call the method form when you need options:
43
35
 
44
- ## Quick tour
36
+ ```python
37
+ value = hx.from_hex("deadbeef")
45
38
 
46
- Use direct helpers when you want one obvious conversion across many
47
- representations:
39
+ value.to_hex()
40
+ # 'deadbeef' (same as value.hex)
48
41
 
49
- ```python
50
- hx.from_hex("de ad be ef").bytes
42
+ value.to_hex(sep=" ", uppercase=True)
43
+ # 'DE AD BE EF'
44
+
45
+ value.to_bytes()
51
46
  # b'\xde\xad\xbe\xef'
52
47
 
53
- hx.from_text("data").to_hex_array(prefix=True)
54
- # ['0x64', '0x61', '0x74', '0x61']
48
+ hx.from_hex("68656c6c6f").to_text()
49
+ # 'hello'
50
+ ```
55
51
 
56
- hx.from_int(0xdeadbeef).bytes
57
- # b'\xde\xad\xbe\xef'
52
+ ## Fast compose
58
53
 
59
- hx.from_int_array([0x1234, 0x5678], width=2).to_hex_array(width=2)
60
- # ['1234', '5678']
54
+ Create your own converters by snapping together
55
+ `source format >> optional transforms >> target format`.
61
56
 
62
- hx.from_binary("01100100 01100001 01110100 01100001").text
63
- # 'data'
57
+ ```python
58
+ to_bytes = hx.Hex() >> hx.Bytes()
59
+ to_bytes("68 69")
60
+ # b'hi'
64
61
 
65
- hx.from_base64("ZGF0YQ==").text
66
- # 'data'
62
+ spaced_hex = hx.Bytes() >> hx.Hex(sep=" ")
63
+ spaced_hex(b"data")
64
+ # '64 61 74 61'
67
65
 
68
- hx.from_escaped(r"\xde\xad").hex
69
- # 'dead'
66
+ words = hx.Hex() >> hx.Chunk(2) >> hx.IntArray()
67
+ words("12 34 56 78")
68
+ # [4660, 22136]
70
69
 
71
- hx.from_struct((0x1234, 0x5678), fmt=">HH").hex
70
+ pack_to_hex = hx.Struct(">HH") >> hx.Hex()
71
+ pack_to_hex((0x1234, 0x5678))
72
72
  # '12345678'
73
-
74
- hx.from_bits("101", pad=True).hex
75
- # '05'
76
73
  ```
77
74
 
78
- Use `from_auto` when you want a quick best-effort parse:
75
+ ## Configure when needed
76
+
77
+ Formats work bare by default. Add arguments only for the conversion that needs
78
+ them:
79
79
 
80
80
  ```python
81
- hx.from_auto("0xdeadbeef").bytes
81
+ hx.convert("de ad be ef", hx.Hex(), hx.Bytes())
82
82
  # b'\xde\xad\xbe\xef'
83
83
 
84
- hx.from_auto(b"\xde\xad").hex
85
- # 'dead'
84
+ hx.convert(b"\xde\xad\xbe\xef", hx.Bytes(), hx.Hex(sep=" ", prefix=True, uppercase=True))
85
+ # '0xDE AD BE EF'
86
+
87
+ hx.convert("π", hx.Text(encoding="utf-8"), hx.Hex())
88
+ # 'cf80'
86
89
 
87
- hx.from_auto([0xde, 0xad, 0xbe, 0xef]).to(hx.Hex(prefix=True))
88
- # '0xdeadbeef'
90
+ hx.from_int(0x12345678, endian="little").hex
91
+ # '78563412'
92
+
93
+ hx.convert("ZGF0YQ", hx.Base64(padding=False), hx.Text())
94
+ # 'data'
95
+
96
+ hx.from_binary("00010110 10010110", bit_order="lsb").text
97
+ # 'hi'
89
98
  ```
90
99
 
91
- ## Composable interface
100
+ Hex strings may include common separators, so you do not need to manually strip
101
+ spaces, colons, dashes, or `0x` prefixes before converting. `Hex(sep=" ")` is
102
+ how you emit space-separated hex.
103
+
104
+ ## Full pipeline guide
92
105
 
93
106
  `hexconv` is built around small format objects. A format can parse directly:
94
107
 
@@ -99,8 +112,15 @@ hx.Hex()("de ad be ef").bytes
99
112
  hx.Text()("data").hex
100
113
  # '64617461'
101
114
 
102
- hx.Int(width=4, endian="little")(0x12345678).hex
115
+ hx.Int(endian="little")(0x12345678).hex
103
116
  # '78563412'
117
+
118
+ pack_words = hx.Struct(">HH")
119
+ pack_words((0x1234, 0x5678)).hex
120
+ # '12345678'
121
+
122
+ hx.Hex()("12345678").to(pack_words)
123
+ # (4660, 22136)
104
124
  ```
105
125
 
106
126
  Formats compose with `>>`, so reusable converters are normal Python objects:
@@ -113,12 +133,20 @@ to_text([0x48, 0x65, 0x6C, 0x6C, 0x6F])
113
133
  to_hex = hx.Text() >> hx.Hex(prefix=True)
114
134
  to_hex("data")
115
135
  # '0x64617461'
136
+
137
+ pack_to_hex = hx.Struct(">HH") >> hx.Hex()
138
+ pack_to_hex((0x1234, 0x5678))
139
+ # '12345678'
140
+
141
+ unpack_from_hex = hx.Hex() >> hx.Struct(">HH")
142
+ unpack_from_hex("12345678")
143
+ # (4660, 22136)
116
144
  ```
117
145
 
118
146
  Transforms sit between formats when data needs shaping:
119
147
 
120
148
  ```python
121
- words = hx.Hex() >> hx.Chunk(2) >> hx.IntArray(width=2)
149
+ words = hx.Hex() >> hx.Chunk(2) >> hx.IntArray()
122
150
  words("12345678")
123
151
  # [4660, 22136]
124
152
 
@@ -145,89 +173,27 @@ conv("12345678")
145
173
  # ['0x1234', '0x5678']
146
174
  ```
147
175
 
148
- ## Configurable one-shot conversions
149
-
150
- Use `convert` when you want an explicit source and target in one expression:
151
-
152
- ```python
153
- hx.convert("de ad be ef", hx.Hex(sep=" "), hx.Bytes())
154
- # b'\xde\xad\xbe\xef'
155
-
156
- hx.convert(b"\xde\xad\xbe\xef", hx.Bytes(), hx.Hex(sep=" "))
157
- # 'de ad be ef'
158
-
159
- hx.convert("data", hx.Text(), hx.Hex(prefix=True))
160
- # '0x64617461'
161
-
162
- hx.convert("π", hx.Text(encoding="utf-8"), hx.Hex())
163
- # 'cf80'
164
-
165
- hx.convert("-_8", hx.Base64(urlsafe=True, padding=False), hx.Hex())
166
- # 'fbff'
167
- ```
168
-
169
- Hex strings may include common separators, so you do not need to manually strip
170
- spaces, colons, dashes, or `0x` prefixes before converting.
171
-
172
- ## Common conversion patterns
173
-
174
- Text, bytes, and hex:
175
-
176
- ```python
177
- hx.Text()("hello").bytes
178
- # b'hello'
179
-
180
- hx.Hex()("68656c6c6f").text
181
- # 'hello'
182
-
183
- hx.BytesArray()([0x68, 0x69]).to(hx.Text())
184
- # 'hi'
185
- ```
186
-
187
- Integer packing:
176
+ More conversion patterns:
188
177
 
189
178
  ```python
190
- hx.Int(width=2)(0x1234).hex
191
- # '1234'
179
+ hx.BytesArray()([0x4F, 0x4B]).to(hx.Text())
180
+ # 'OK'
192
181
 
193
- hx.Int(width=2, endian="little")(0x1234).hex
182
+ hx.Int(endian="little")(0x1234).hex
194
183
  # '3412'
195
184
 
196
- (hx.Hex() >> hx.Chunk(2) >> hx.IntArray(width=2))("12345678")
197
- # [4660, 22136]
198
- ```
199
-
200
- Base encodings:
201
-
202
- ```python
203
- hx.Text()("data").to(hx.Base64())
204
- # 'ZGF0YQ=='
205
-
206
185
  hx.Text()("data").to(hx.Base32(padding=False))
207
186
  # 'MRQXIYI'
208
187
 
209
- hx.Base64(urlsafe=True, padding=False)("-_8").hex
210
- # 'fbff'
211
- ```
212
-
213
- Escaped strings, hexdumps, structs, and bits:
214
-
215
- ```python
216
- hx.Escaped()(r"\xde\xad").hex
217
- # 'dead'
218
-
219
- dump = hx.Hex()("deadbeef").to(hx.Hexdump(width=2))
220
- hx.Hexdump()(dump).hex
221
- # 'deadbeef'
222
-
223
- hx.Struct(">HH")((0x1234, 0x5678)).hex
224
- # '12345678'
188
+ dump = hx.Text()("data").to(hx.Hexdump(width=2))
189
+ hx.Hexdump()(dump).text
190
+ # 'data'
225
191
 
226
192
  hx.Hex()("12345678").to(hx.Struct(">HH"))
227
193
  # (4660, 22136)
228
194
 
229
- hx.Bits()([1, 0, 1]).hex
230
- # '05'
195
+ hx.Bits()("0100111101001011").text
196
+ # 'OK'
231
197
  ```
232
198
 
233
199
  ## Why explicit formats?
@@ -275,10 +241,10 @@ result.reason
275
241
  `from_auto(..., explain=True)` returns the same explanation object:
276
242
 
277
243
  ```python
278
- result = hx.from_auto("0b101", explain=True)
244
+ result = hx.from_auto("0b0100111101001011", explain=True)
279
245
 
280
- result.value.hex
281
- # '05'
246
+ result.value.text
247
+ # 'OK'
282
248
  ```
283
249
 
284
250
  ## Design priorities
@@ -302,7 +268,7 @@ conv("deadbeef")
302
268
  # 3735928559
303
269
  ```
304
270
 
305
- Available format specs:
271
+ Available format specs all work in their simplest bare form:
306
272
 
307
273
  - `Bytes()`
308
274
  - `BytesArray()`
@@ -310,8 +276,8 @@ Available format specs:
310
276
  - `Hex()`
311
277
  - `HexArray()`
312
278
  - `HexInt()` / `LargeHexNumber()`
313
- - `Int()`
314
- - `IntArray()`
279
+ - `Int()` / `DecimalInt()`
280
+ - `IntArray()` / `DecimalIntArray()`
315
281
  - `Text()`
316
282
  - `Binary()`
317
283
  - `Base64()`
@@ -322,6 +288,20 @@ Available format specs:
322
288
  - `Hexdump()`
323
289
  - `Struct(fmt)`
324
290
  - `Bits()`
291
+ - `Auto()`
292
+
293
+ Add options only when you need control over formatting or parsing:
294
+
295
+ - Display: `Hex(sep=" ", prefix=True, uppercase=True)`, `HexArray(width=2)`.
296
+ - Integer packing: `Int(width=4)`, `Int(endian="little")`, `IntArray(width=2)`.
297
+ - Text: `Text(encoding="utf-8", errors="replace")`.
298
+ - Base encodings: `Base64(urlsafe=True, padding=False)`, `Base32(padding=False)`.
299
+ - Binary/bits: `Binary(sep=" ", prefix=True, bit_order="lsb")`, `Bits(pad_side="right")`.
300
+ - Dumps/escapes/structs: `Hexdump(width=8)`, `Escaped(uppercase=True)`, `Struct(">HH")`.
301
+
302
+ Some options only matter in one direction. For example, `Hex(sep=" ")`
303
+ controls hex output formatting, while hex input already accepts common
304
+ separators such as spaces, colons, dashes, underscores, and `0x` prefixes.
325
305
 
326
306
  ## Transforms
327
307
 
@@ -329,7 +309,7 @@ Transforms are byte-to-byte steps that sit between input and output formats.
329
309
 
330
310
  ```python
331
311
  hx.Hex() >> hx.Chunk(2) >> hx.HexArray()
332
- hx.Hex() >> hx.Group(2) >> hx.IntArray(width=2)
312
+ hx.Hex() >> hx.Group(2) >> hx.IntArray()
333
313
  hx.Hex() >> hx.Pad.left(width=8) >> hx.Hex()
334
314
  hx.Hex() >> hx.Pad.right(block_size=8, byte=0xFF) >> hx.Hex()
335
315
  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.4"
7
+ version = "0.2.6"
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.4
3
+ Version: 0.2.6
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,83 +41,96 @@ It is built around ergonomic one-liners and composable format objects.
41
41
  pip install hexconv
42
42
  ```
43
43
 
44
- ## Fast compose
44
+ ## Simple usage
45
45
 
46
- The intended interface is small pieces snapped together:
47
- `source format >> optional transforms >> target format`.
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.
48
48
 
49
49
  ```python
50
50
  import hexconv as hx
51
51
 
52
- to_bytes = hx.Hex() >> hx.Bytes()
53
- to_bytes("de ad be ef")
54
- # b'\xde\xad\xbe\xef'
55
-
56
- spaced_hex = hx.Bytes() >> hx.Hex(sep=" ")
57
- spaced_hex(b"\xde\xad\xbe\xef")
58
- # 'de ad be ef'
52
+ hx.from_auto("0x64617461").text
53
+ # 'data'
59
54
 
60
- words = hx.Hex(sep=" ") >> hx.Chunk(2) >> hx.IntArray(width=2)
61
- words("12 34 56 78")
62
- # [4660, 22136]
55
+ hx.from_bytes_array([0xde, 0xad, 0xbe, 0xef]).int
56
+ # 3735928559
63
57
 
64
- text_to_urlsafe = hx.Text() >> hx.Base64(urlsafe=True, padding=False)
65
- text_to_urlsafe("data")
66
- # 'ZGF0YQ'
58
+ hx.from_text("data").hex
59
+ # '64617461'
67
60
  ```
68
61
 
69
- Hex input accepts common separators, so spaced or copied hex usually does not
70
- need manual cleanup before conversion. `Hex(sep=" ")` is also how you emit
71
- space-separated hex.
62
+ The bare `.hex`, `.text`, and `.bytes` properties are shortcuts for zero-argument
63
+ `to_*` methods. Call the method form when you need options:
72
64
 
73
- ## Quick tour
65
+ ```python
66
+ value = hx.from_hex("deadbeef")
74
67
 
75
- Use direct helpers when you want one obvious conversion across many
76
- representations:
68
+ value.to_hex()
69
+ # 'deadbeef' (same as value.hex)
77
70
 
78
- ```python
79
- hx.from_hex("de ad be ef").bytes
71
+ value.to_hex(sep=" ", uppercase=True)
72
+ # 'DE AD BE EF'
73
+
74
+ value.to_bytes()
80
75
  # b'\xde\xad\xbe\xef'
81
76
 
82
- hx.from_text("data").to_hex_array(prefix=True)
83
- # ['0x64', '0x61', '0x74', '0x61']
77
+ hx.from_hex("68656c6c6f").to_text()
78
+ # 'hello'
79
+ ```
84
80
 
85
- hx.from_int(0xdeadbeef).bytes
86
- # b'\xde\xad\xbe\xef'
81
+ ## Fast compose
87
82
 
88
- hx.from_int_array([0x1234, 0x5678], width=2).to_hex_array(width=2)
89
- # ['1234', '5678']
83
+ Create your own converters by snapping together
84
+ `source format >> optional transforms >> target format`.
90
85
 
91
- hx.from_binary("01100100 01100001 01110100 01100001").text
92
- # 'data'
86
+ ```python
87
+ to_bytes = hx.Hex() >> hx.Bytes()
88
+ to_bytes("68 69")
89
+ # b'hi'
93
90
 
94
- hx.from_base64("ZGF0YQ==").text
95
- # 'data'
91
+ spaced_hex = hx.Bytes() >> hx.Hex(sep=" ")
92
+ spaced_hex(b"data")
93
+ # '64 61 74 61'
96
94
 
97
- hx.from_escaped(r"\xde\xad").hex
98
- # 'dead'
95
+ words = hx.Hex() >> hx.Chunk(2) >> hx.IntArray()
96
+ words("12 34 56 78")
97
+ # [4660, 22136]
99
98
 
100
- hx.from_struct((0x1234, 0x5678), fmt=">HH").hex
99
+ pack_to_hex = hx.Struct(">HH") >> hx.Hex()
100
+ pack_to_hex((0x1234, 0x5678))
101
101
  # '12345678'
102
-
103
- hx.from_bits("101", pad=True).hex
104
- # '05'
105
102
  ```
106
103
 
107
- Use `from_auto` when you want a quick best-effort parse:
104
+ ## Configure when needed
105
+
106
+ Formats work bare by default. Add arguments only for the conversion that needs
107
+ them:
108
108
 
109
109
  ```python
110
- hx.from_auto("0xdeadbeef").bytes
110
+ hx.convert("de ad be ef", hx.Hex(), hx.Bytes())
111
111
  # b'\xde\xad\xbe\xef'
112
112
 
113
- hx.from_auto(b"\xde\xad").hex
114
- # 'dead'
113
+ hx.convert(b"\xde\xad\xbe\xef", hx.Bytes(), hx.Hex(sep=" ", prefix=True, uppercase=True))
114
+ # '0xDE AD BE EF'
115
+
116
+ hx.convert("π", hx.Text(encoding="utf-8"), hx.Hex())
117
+ # 'cf80'
115
118
 
116
- hx.from_auto([0xde, 0xad, 0xbe, 0xef]).to(hx.Hex(prefix=True))
117
- # '0xdeadbeef'
119
+ hx.from_int(0x12345678, endian="little").hex
120
+ # '78563412'
121
+
122
+ hx.convert("ZGF0YQ", hx.Base64(padding=False), hx.Text())
123
+ # 'data'
124
+
125
+ hx.from_binary("00010110 10010110", bit_order="lsb").text
126
+ # 'hi'
118
127
  ```
119
128
 
120
- ## Composable interface
129
+ Hex strings may include common separators, so you do not need to manually strip
130
+ spaces, colons, dashes, or `0x` prefixes before converting. `Hex(sep=" ")` is
131
+ how you emit space-separated hex.
132
+
133
+ ## Full pipeline guide
121
134
 
122
135
  `hexconv` is built around small format objects. A format can parse directly:
123
136
 
@@ -128,8 +141,15 @@ hx.Hex()("de ad be ef").bytes
128
141
  hx.Text()("data").hex
129
142
  # '64617461'
130
143
 
131
- hx.Int(width=4, endian="little")(0x12345678).hex
144
+ hx.Int(endian="little")(0x12345678).hex
132
145
  # '78563412'
146
+
147
+ pack_words = hx.Struct(">HH")
148
+ pack_words((0x1234, 0x5678)).hex
149
+ # '12345678'
150
+
151
+ hx.Hex()("12345678").to(pack_words)
152
+ # (4660, 22136)
133
153
  ```
134
154
 
135
155
  Formats compose with `>>`, so reusable converters are normal Python objects:
@@ -142,12 +162,20 @@ to_text([0x48, 0x65, 0x6C, 0x6C, 0x6F])
142
162
  to_hex = hx.Text() >> hx.Hex(prefix=True)
143
163
  to_hex("data")
144
164
  # '0x64617461'
165
+
166
+ pack_to_hex = hx.Struct(">HH") >> hx.Hex()
167
+ pack_to_hex((0x1234, 0x5678))
168
+ # '12345678'
169
+
170
+ unpack_from_hex = hx.Hex() >> hx.Struct(">HH")
171
+ unpack_from_hex("12345678")
172
+ # (4660, 22136)
145
173
  ```
146
174
 
147
175
  Transforms sit between formats when data needs shaping:
148
176
 
149
177
  ```python
150
- words = hx.Hex() >> hx.Chunk(2) >> hx.IntArray(width=2)
178
+ words = hx.Hex() >> hx.Chunk(2) >> hx.IntArray()
151
179
  words("12345678")
152
180
  # [4660, 22136]
153
181
 
@@ -174,89 +202,27 @@ conv("12345678")
174
202
  # ['0x1234', '0x5678']
175
203
  ```
176
204
 
177
- ## Configurable one-shot conversions
178
-
179
- Use `convert` when you want an explicit source and target in one expression:
180
-
181
- ```python
182
- hx.convert("de ad be ef", hx.Hex(sep=" "), hx.Bytes())
183
- # b'\xde\xad\xbe\xef'
184
-
185
- hx.convert(b"\xde\xad\xbe\xef", hx.Bytes(), hx.Hex(sep=" "))
186
- # 'de ad be ef'
187
-
188
- hx.convert("data", hx.Text(), hx.Hex(prefix=True))
189
- # '0x64617461'
190
-
191
- hx.convert("π", hx.Text(encoding="utf-8"), hx.Hex())
192
- # 'cf80'
193
-
194
- hx.convert("-_8", hx.Base64(urlsafe=True, padding=False), hx.Hex())
195
- # 'fbff'
196
- ```
197
-
198
- Hex strings may include common separators, so you do not need to manually strip
199
- spaces, colons, dashes, or `0x` prefixes before converting.
200
-
201
- ## Common conversion patterns
202
-
203
- Text, bytes, and hex:
204
-
205
- ```python
206
- hx.Text()("hello").bytes
207
- # b'hello'
208
-
209
- hx.Hex()("68656c6c6f").text
210
- # 'hello'
211
-
212
- hx.BytesArray()([0x68, 0x69]).to(hx.Text())
213
- # 'hi'
214
- ```
215
-
216
- Integer packing:
205
+ More conversion patterns:
217
206
 
218
207
  ```python
219
- hx.Int(width=2)(0x1234).hex
220
- # '1234'
208
+ hx.BytesArray()([0x4F, 0x4B]).to(hx.Text())
209
+ # 'OK'
221
210
 
222
- hx.Int(width=2, endian="little")(0x1234).hex
211
+ hx.Int(endian="little")(0x1234).hex
223
212
  # '3412'
224
213
 
225
- (hx.Hex() >> hx.Chunk(2) >> hx.IntArray(width=2))("12345678")
226
- # [4660, 22136]
227
- ```
228
-
229
- Base encodings:
230
-
231
- ```python
232
- hx.Text()("data").to(hx.Base64())
233
- # 'ZGF0YQ=='
234
-
235
214
  hx.Text()("data").to(hx.Base32(padding=False))
236
215
  # 'MRQXIYI'
237
216
 
238
- hx.Base64(urlsafe=True, padding=False)("-_8").hex
239
- # 'fbff'
240
- ```
241
-
242
- Escaped strings, hexdumps, structs, and bits:
243
-
244
- ```python
245
- hx.Escaped()(r"\xde\xad").hex
246
- # 'dead'
247
-
248
- dump = hx.Hex()("deadbeef").to(hx.Hexdump(width=2))
249
- hx.Hexdump()(dump).hex
250
- # 'deadbeef'
251
-
252
- hx.Struct(">HH")((0x1234, 0x5678)).hex
253
- # '12345678'
217
+ dump = hx.Text()("data").to(hx.Hexdump(width=2))
218
+ hx.Hexdump()(dump).text
219
+ # 'data'
254
220
 
255
221
  hx.Hex()("12345678").to(hx.Struct(">HH"))
256
222
  # (4660, 22136)
257
223
 
258
- hx.Bits()([1, 0, 1]).hex
259
- # '05'
224
+ hx.Bits()("0100111101001011").text
225
+ # 'OK'
260
226
  ```
261
227
 
262
228
  ## Why explicit formats?
@@ -304,10 +270,10 @@ result.reason
304
270
  `from_auto(..., explain=True)` returns the same explanation object:
305
271
 
306
272
  ```python
307
- result = hx.from_auto("0b101", explain=True)
273
+ result = hx.from_auto("0b0100111101001011", explain=True)
308
274
 
309
- result.value.hex
310
- # '05'
275
+ result.value.text
276
+ # 'OK'
311
277
  ```
312
278
 
313
279
  ## Design priorities
@@ -331,7 +297,7 @@ conv("deadbeef")
331
297
  # 3735928559
332
298
  ```
333
299
 
334
- Available format specs:
300
+ Available format specs all work in their simplest bare form:
335
301
 
336
302
  - `Bytes()`
337
303
  - `BytesArray()`
@@ -339,8 +305,8 @@ Available format specs:
339
305
  - `Hex()`
340
306
  - `HexArray()`
341
307
  - `HexInt()` / `LargeHexNumber()`
342
- - `Int()`
343
- - `IntArray()`
308
+ - `Int()` / `DecimalInt()`
309
+ - `IntArray()` / `DecimalIntArray()`
344
310
  - `Text()`
345
311
  - `Binary()`
346
312
  - `Base64()`
@@ -351,6 +317,20 @@ Available format specs:
351
317
  - `Hexdump()`
352
318
  - `Struct(fmt)`
353
319
  - `Bits()`
320
+ - `Auto()`
321
+
322
+ Add options only when you need control over formatting or parsing:
323
+
324
+ - Display: `Hex(sep=" ", prefix=True, uppercase=True)`, `HexArray(width=2)`.
325
+ - Integer packing: `Int(width=4)`, `Int(endian="little")`, `IntArray(width=2)`.
326
+ - Text: `Text(encoding="utf-8", errors="replace")`.
327
+ - Base encodings: `Base64(urlsafe=True, padding=False)`, `Base32(padding=False)`.
328
+ - Binary/bits: `Binary(sep=" ", prefix=True, bit_order="lsb")`, `Bits(pad_side="right")`.
329
+ - Dumps/escapes/structs: `Hexdump(width=8)`, `Escaped(uppercase=True)`, `Struct(">HH")`.
330
+
331
+ Some options only matter in one direction. For example, `Hex(sep=" ")`
332
+ controls hex output formatting, while hex input already accepts common
333
+ separators such as spaces, colons, dashes, underscores, and `0x` prefixes.
354
334
 
355
335
  ## Transforms
356
336
 
@@ -358,7 +338,7 @@ Transforms are byte-to-byte steps that sit between input and output formats.
358
338
 
359
339
  ```python
360
340
  hx.Hex() >> hx.Chunk(2) >> hx.HexArray()
361
- hx.Hex() >> hx.Group(2) >> hx.IntArray(width=2)
341
+ hx.Hex() >> hx.Group(2) >> hx.IntArray()
362
342
  hx.Hex() >> hx.Pad.left(width=8) >> hx.Hex()
363
343
  hx.Hex() >> hx.Pad.right(block_size=8, byte=0xFF) >> hx.Hex()
364
344
  hx.Hex() >> hx.Reverse() >> hx.Hex()
@@ -45,11 +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(sep=" "), hx.Bytes()) == b"\xde\xad\xbe\xef"
48
+ assert hx.convert("de ad be ef", hx.Hex(), hx.Bytes()) == b"\xde\xad\xbe\xef"
49
49
  assert hx.convert(b"\xde\xad\xbe\xef", hx.Bytes(), hx.Hex(sep=" ")) == "de ad be ef"
50
50
  assert hx.convert("data", hx.Text(), hx.Hex(prefix=True)) == "0x64617461"
51
51
 
52
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
+
53
98
  def test_convert_rejects_mixed_positional_and_keyword_formats():
54
99
  with pytest.raises(hx.HexConvError, match="from_"):
55
100
  hx.convert("data", hx.Text(), from_=hx.Text(), to=hx.Hex())
@@ -115,10 +160,10 @@ def test_constructable_hex_and_text_specs():
115
160
 
116
161
 
117
162
  def test_pipeline_builder_and_shift_composition():
118
- conv = hx.pipeline().from_(hx.Hex(sep=" ")).chunk(2).to(hx.IntArray(width=2))
163
+ conv = hx.pipeline().from_(hx.Hex()).chunk(2).to(hx.IntArray())
119
164
  assert conv("12 34 56 78") == [0x1234, 0x5678]
120
165
 
121
- shift_conv = hx.Hex(sep=" ") >> hx.Chunk(2) >> hx.HexArray()
166
+ shift_conv = hx.Hex() >> hx.Chunk(2) >> hx.HexArray()
122
167
  assert shift_conv("12 34 56 78") == ["1234", "5678"]
123
168
 
124
169
 
@@ -161,6 +206,9 @@ def test_struct_format_pack_and_unpack():
161
206
  assert packed.hex == "12345678"
162
207
  assert packed.to(hx.Struct(">HH")) == (0x1234, 0x5678)
163
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)
164
212
 
165
213
 
166
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