hexconv 0.2.1__tar.gz → 0.2.3__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.1/src/hexconv.egg-info → hexconv-0.2.3}/PKG-INFO +73 -25
- {hexconv-0.2.1 → hexconv-0.2.3}/README.md +72 -24
- {hexconv-0.2.1 → hexconv-0.2.3}/pyproject.toml +1 -1
- {hexconv-0.2.1 → hexconv-0.2.3}/src/hexconv/_core.py +22 -5
- {hexconv-0.2.1 → hexconv-0.2.3/src/hexconv.egg-info}/PKG-INFO +73 -25
- {hexconv-0.2.1 → hexconv-0.2.3}/tests/test_hexconv.py +9 -0
- {hexconv-0.2.1 → hexconv-0.2.3}/LICENSE +0 -0
- {hexconv-0.2.1 → hexconv-0.2.3}/MANIFEST.in +0 -0
- {hexconv-0.2.1 → hexconv-0.2.3}/setup.cfg +0 -0
- {hexconv-0.2.1 → hexconv-0.2.3}/src/hexconv/__init__.py +0 -0
- {hexconv-0.2.1 → hexconv-0.2.3}/src/hexconv/py.typed +0 -0
- {hexconv-0.2.1 → hexconv-0.2.3}/src/hexconv.egg-info/SOURCES.txt +0 -0
- {hexconv-0.2.1 → hexconv-0.2.3}/src/hexconv.egg-info/dependency_links.txt +0 -0
- {hexconv-0.2.1 → hexconv-0.2.3}/src/hexconv.egg-info/requires.txt +0 -0
- {hexconv-0.2.1 → hexconv-0.2.3}/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.3
|
|
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
|
|
@@ -31,18 +31,9 @@ Dynamic: license-file
|
|
|
31
31
|
|
|
32
32
|
`hexconv` is a small, dependency-free Python toolkit for converting between
|
|
33
33
|
bytes, hex, integers, arrays, binary strings, base encodings, escaped strings,
|
|
34
|
-
hexdumps, and text.
|
|
34
|
+
hexdumps, structs, bits, and text.
|
|
35
35
|
|
|
36
|
-
It is
|
|
37
|
-
|
|
38
|
-
```python
|
|
39
|
-
import hexconv as hx
|
|
40
|
-
|
|
41
|
-
decode = hx.HexArray() >> hx.Text()
|
|
42
|
-
|
|
43
|
-
decode([0x3C, 0x4D, 0x41, 0x47])
|
|
44
|
-
# '<MAG'
|
|
45
|
-
```
|
|
36
|
+
It is built around ergonomic one-liners and composable format objects.
|
|
46
37
|
|
|
47
38
|
## Install
|
|
48
39
|
|
|
@@ -50,19 +41,33 @@ decode([0x3C, 0x4D, 0x41, 0x47])
|
|
|
50
41
|
pip install hexconv
|
|
51
42
|
```
|
|
52
43
|
|
|
53
|
-
##
|
|
44
|
+
## Quick tour
|
|
54
45
|
|
|
55
|
-
Use
|
|
46
|
+
Use direct helpers when you want one obvious conversion:
|
|
56
47
|
|
|
57
48
|
```python
|
|
58
|
-
hx
|
|
49
|
+
import hexconv as hx
|
|
50
|
+
|
|
51
|
+
hx.from_hex("dead beef").to_bytes()
|
|
59
52
|
# b'\xde\xad\xbe\xef'
|
|
60
53
|
|
|
61
|
-
hx.
|
|
62
|
-
# '
|
|
54
|
+
hx.from_hex("dead beef").bytes
|
|
55
|
+
# b'\xde\xad\xbe\xef'
|
|
63
56
|
|
|
64
|
-
hx.
|
|
65
|
-
# '
|
|
57
|
+
hx.from_bytes_array([0xde, 0xad, 0xbe, 0xef]).to_hex()
|
|
58
|
+
# 'deadbeef'
|
|
59
|
+
|
|
60
|
+
hx.from_bytes_array([0xde, 0xad, 0xbe, 0xef]).hex
|
|
61
|
+
# 'deadbeef'
|
|
62
|
+
|
|
63
|
+
hx.from_text("data").to_hex_array(prefix=True)
|
|
64
|
+
# ['0x64', '0x61', '0x74', '0x61']
|
|
65
|
+
|
|
66
|
+
hx.from_int(0xdeadbeef).to_bytes()
|
|
67
|
+
# b'\xde\xad\xbe\xef'
|
|
68
|
+
|
|
69
|
+
hx.from_int_array([0x1234, 0x5678], width=2).to_hex_array(width=2)
|
|
70
|
+
# ['1234', '5678']
|
|
66
71
|
```
|
|
67
72
|
|
|
68
73
|
Use `from_auto` when you want a quick best-effort parse:
|
|
@@ -78,19 +83,34 @@ hx.from_auto([0xde, 0xad, 0xbe, 0xef]).to(hx.Hex(prefix=True))
|
|
|
78
83
|
# '0xdeadbeef'
|
|
79
84
|
```
|
|
80
85
|
|
|
81
|
-
|
|
86
|
+
## Composable interface
|
|
87
|
+
|
|
88
|
+
`hexconv` is built around small format objects. A format can parse directly:
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
hx.Hex()("dead beef").bytes
|
|
92
|
+
# b'\xde\xad\xbe\xef'
|
|
93
|
+
|
|
94
|
+
hx.Text()("data").hex
|
|
95
|
+
# '64617461'
|
|
96
|
+
|
|
97
|
+
hx.Int(width=4, endian="little")(0x12345678).hex
|
|
98
|
+
# '78563412'
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Formats compose with `>>`:
|
|
82
102
|
|
|
83
103
|
```python
|
|
84
104
|
to_text = hx.HexArray() >> hx.Text()
|
|
85
|
-
to_text([
|
|
86
|
-
# '
|
|
105
|
+
to_text([0x48, 0x65, 0x6C, 0x6C, 0x6F])
|
|
106
|
+
# 'Hello'
|
|
87
107
|
|
|
88
108
|
to_hex = hx.Text() >> hx.Hex(prefix=True)
|
|
89
109
|
to_hex("data")
|
|
90
110
|
# '0x64617461'
|
|
91
111
|
```
|
|
92
112
|
|
|
93
|
-
|
|
113
|
+
Transforms sit between formats when data needs shaping:
|
|
94
114
|
|
|
95
115
|
```python
|
|
96
116
|
words = hx.Hex() >> hx.Chunk(2) >> hx.IntArray(width=2)
|
|
@@ -106,7 +126,7 @@ pad_hex("dead")
|
|
|
106
126
|
# '0000dead'
|
|
107
127
|
```
|
|
108
128
|
|
|
109
|
-
Use the builder form when
|
|
129
|
+
Use the builder form when named steps read better:
|
|
110
130
|
|
|
111
131
|
```python
|
|
112
132
|
conv = (
|
|
@@ -120,7 +140,28 @@ conv("12345678")
|
|
|
120
140
|
# ['0x1234', '0x5678']
|
|
121
141
|
```
|
|
122
142
|
|
|
123
|
-
##
|
|
143
|
+
## Configurable one-shot conversions
|
|
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
|
|
124
165
|
|
|
125
166
|
Text, bytes, and hex:
|
|
126
167
|
|
|
@@ -232,6 +273,13 @@ result.value.hex
|
|
|
232
273
|
# '05'
|
|
233
274
|
```
|
|
234
275
|
|
|
276
|
+
## Design priorities
|
|
277
|
+
|
|
278
|
+
- Easy: obvious conversions stay one-liners.
|
|
279
|
+
- Composable: reusable converters are just `format >> transform >> format`.
|
|
280
|
+
- Flexible: configure endianness, width, padding, grouping, text encoding, and base encodings where needed.
|
|
281
|
+
- Fast and lightweight: no runtime dependencies, bytes-native internals, and direct use of Python's optimized `bytes`, `int`, `base64`, and `struct` primitives.
|
|
282
|
+
|
|
235
283
|
## Format objects
|
|
236
284
|
|
|
237
285
|
Format objects are both parsers and pipeline endpoints.
|
|
@@ -2,18 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
`hexconv` is a small, dependency-free Python toolkit for converting between
|
|
4
4
|
bytes, hex, integers, arrays, binary strings, base encodings, escaped strings,
|
|
5
|
-
hexdumps, and text.
|
|
5
|
+
hexdumps, structs, bits, and text.
|
|
6
6
|
|
|
7
|
-
It is
|
|
8
|
-
|
|
9
|
-
```python
|
|
10
|
-
import hexconv as hx
|
|
11
|
-
|
|
12
|
-
decode = hx.HexArray() >> hx.Text()
|
|
13
|
-
|
|
14
|
-
decode([0x3C, 0x4D, 0x41, 0x47])
|
|
15
|
-
# '<MAG'
|
|
16
|
-
```
|
|
7
|
+
It is built around ergonomic one-liners and composable format objects.
|
|
17
8
|
|
|
18
9
|
## Install
|
|
19
10
|
|
|
@@ -21,19 +12,33 @@ decode([0x3C, 0x4D, 0x41, 0x47])
|
|
|
21
12
|
pip install hexconv
|
|
22
13
|
```
|
|
23
14
|
|
|
24
|
-
##
|
|
15
|
+
## Quick tour
|
|
25
16
|
|
|
26
|
-
Use
|
|
17
|
+
Use direct helpers when you want one obvious conversion:
|
|
27
18
|
|
|
28
19
|
```python
|
|
29
|
-
hx
|
|
20
|
+
import hexconv as hx
|
|
21
|
+
|
|
22
|
+
hx.from_hex("dead beef").to_bytes()
|
|
30
23
|
# b'\xde\xad\xbe\xef'
|
|
31
24
|
|
|
32
|
-
hx.
|
|
33
|
-
# '
|
|
25
|
+
hx.from_hex("dead beef").bytes
|
|
26
|
+
# b'\xde\xad\xbe\xef'
|
|
34
27
|
|
|
35
|
-
hx.
|
|
36
|
-
# '
|
|
28
|
+
hx.from_bytes_array([0xde, 0xad, 0xbe, 0xef]).to_hex()
|
|
29
|
+
# 'deadbeef'
|
|
30
|
+
|
|
31
|
+
hx.from_bytes_array([0xde, 0xad, 0xbe, 0xef]).hex
|
|
32
|
+
# 'deadbeef'
|
|
33
|
+
|
|
34
|
+
hx.from_text("data").to_hex_array(prefix=True)
|
|
35
|
+
# ['0x64', '0x61', '0x74', '0x61']
|
|
36
|
+
|
|
37
|
+
hx.from_int(0xdeadbeef).to_bytes()
|
|
38
|
+
# b'\xde\xad\xbe\xef'
|
|
39
|
+
|
|
40
|
+
hx.from_int_array([0x1234, 0x5678], width=2).to_hex_array(width=2)
|
|
41
|
+
# ['1234', '5678']
|
|
37
42
|
```
|
|
38
43
|
|
|
39
44
|
Use `from_auto` when you want a quick best-effort parse:
|
|
@@ -49,19 +54,34 @@ hx.from_auto([0xde, 0xad, 0xbe, 0xef]).to(hx.Hex(prefix=True))
|
|
|
49
54
|
# '0xdeadbeef'
|
|
50
55
|
```
|
|
51
56
|
|
|
52
|
-
|
|
57
|
+
## Composable interface
|
|
58
|
+
|
|
59
|
+
`hexconv` is built around small format objects. A format can parse directly:
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
hx.Hex()("dead beef").bytes
|
|
63
|
+
# b'\xde\xad\xbe\xef'
|
|
64
|
+
|
|
65
|
+
hx.Text()("data").hex
|
|
66
|
+
# '64617461'
|
|
67
|
+
|
|
68
|
+
hx.Int(width=4, endian="little")(0x12345678).hex
|
|
69
|
+
# '78563412'
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Formats compose with `>>`:
|
|
53
73
|
|
|
54
74
|
```python
|
|
55
75
|
to_text = hx.HexArray() >> hx.Text()
|
|
56
|
-
to_text([
|
|
57
|
-
# '
|
|
76
|
+
to_text([0x48, 0x65, 0x6C, 0x6C, 0x6F])
|
|
77
|
+
# 'Hello'
|
|
58
78
|
|
|
59
79
|
to_hex = hx.Text() >> hx.Hex(prefix=True)
|
|
60
80
|
to_hex("data")
|
|
61
81
|
# '0x64617461'
|
|
62
82
|
```
|
|
63
83
|
|
|
64
|
-
|
|
84
|
+
Transforms sit between formats when data needs shaping:
|
|
65
85
|
|
|
66
86
|
```python
|
|
67
87
|
words = hx.Hex() >> hx.Chunk(2) >> hx.IntArray(width=2)
|
|
@@ -77,7 +97,7 @@ pad_hex("dead")
|
|
|
77
97
|
# '0000dead'
|
|
78
98
|
```
|
|
79
99
|
|
|
80
|
-
Use the builder form when
|
|
100
|
+
Use the builder form when named steps read better:
|
|
81
101
|
|
|
82
102
|
```python
|
|
83
103
|
conv = (
|
|
@@ -91,7 +111,28 @@ conv("12345678")
|
|
|
91
111
|
# ['0x1234', '0x5678']
|
|
92
112
|
```
|
|
93
113
|
|
|
94
|
-
##
|
|
114
|
+
## Configurable one-shot conversions
|
|
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
|
|
95
136
|
|
|
96
137
|
Text, bytes, and hex:
|
|
97
138
|
|
|
@@ -203,6 +244,13 @@ result.value.hex
|
|
|
203
244
|
# '05'
|
|
204
245
|
```
|
|
205
246
|
|
|
247
|
+
## Design priorities
|
|
248
|
+
|
|
249
|
+
- Easy: obvious conversions stay one-liners.
|
|
250
|
+
- Composable: reusable converters are just `format >> transform >> format`.
|
|
251
|
+
- Flexible: configure endianness, width, padding, grouping, text encoding, and base encodings where needed.
|
|
252
|
+
- Fast and lightweight: no runtime dependencies, bytes-native internals, and direct use of Python's optimized `bytes`, `int`, `base64`, and `struct` primitives.
|
|
253
|
+
|
|
206
254
|
## Format objects
|
|
207
255
|
|
|
208
256
|
Format objects are both parsers and pipeline endpoints.
|
|
@@ -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.3"
|
|
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"
|
|
@@ -999,17 +999,34 @@ class Converter:
|
|
|
999
999
|
|
|
1000
1000
|
def convert(
|
|
1001
1001
|
value: Any,
|
|
1002
|
+
from_format: FormatLike | None = None,
|
|
1003
|
+
to_format: FormatLike | None = None,
|
|
1002
1004
|
*,
|
|
1003
|
-
from_: FormatLike =
|
|
1004
|
-
to: FormatLike =
|
|
1005
|
+
from_: FormatLike | None = None,
|
|
1006
|
+
to: FormatLike | None = None,
|
|
1005
1007
|
input_options: dict[str, Any] | None = None,
|
|
1006
1008
|
output_options: dict[str, Any] | None = None,
|
|
1007
1009
|
) -> Any:
|
|
1008
|
-
"""One-shot conversion between explicit formats.
|
|
1010
|
+
"""One-shot conversion between explicit formats.
|
|
1011
|
+
|
|
1012
|
+
Preferred:
|
|
1013
|
+
convert(value, Hex(), Bytes())
|
|
1014
|
+
|
|
1015
|
+
Backward-compatible:
|
|
1016
|
+
convert(value, from_=Hex(), to=Bytes())
|
|
1017
|
+
"""
|
|
1018
|
+
|
|
1019
|
+
if from_format is not None and from_ is not None:
|
|
1020
|
+
raise HexConvError("use either positional input format or from_, not both")
|
|
1021
|
+
if to_format is not None and to is not None:
|
|
1022
|
+
raise HexConvError("use either positional output format or to, not both")
|
|
1023
|
+
|
|
1024
|
+
input_format = from_format if from_format is not None else from_
|
|
1025
|
+
output_format = to_format if to_format is not None else to
|
|
1009
1026
|
|
|
1010
1027
|
return Converter(
|
|
1011
|
-
|
|
1012
|
-
|
|
1028
|
+
Auto if input_format is None else input_format,
|
|
1029
|
+
Bytes if output_format is None else output_format,
|
|
1013
1030
|
input_options=input_options,
|
|
1014
1031
|
output_options=output_options,
|
|
1015
1032
|
)(value)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hexconv
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
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
|
|
@@ -31,18 +31,9 @@ Dynamic: license-file
|
|
|
31
31
|
|
|
32
32
|
`hexconv` is a small, dependency-free Python toolkit for converting between
|
|
33
33
|
bytes, hex, integers, arrays, binary strings, base encodings, escaped strings,
|
|
34
|
-
hexdumps, and text.
|
|
34
|
+
hexdumps, structs, bits, and text.
|
|
35
35
|
|
|
36
|
-
It is
|
|
37
|
-
|
|
38
|
-
```python
|
|
39
|
-
import hexconv as hx
|
|
40
|
-
|
|
41
|
-
decode = hx.HexArray() >> hx.Text()
|
|
42
|
-
|
|
43
|
-
decode([0x3C, 0x4D, 0x41, 0x47])
|
|
44
|
-
# '<MAG'
|
|
45
|
-
```
|
|
36
|
+
It is built around ergonomic one-liners and composable format objects.
|
|
46
37
|
|
|
47
38
|
## Install
|
|
48
39
|
|
|
@@ -50,19 +41,33 @@ decode([0x3C, 0x4D, 0x41, 0x47])
|
|
|
50
41
|
pip install hexconv
|
|
51
42
|
```
|
|
52
43
|
|
|
53
|
-
##
|
|
44
|
+
## Quick tour
|
|
54
45
|
|
|
55
|
-
Use
|
|
46
|
+
Use direct helpers when you want one obvious conversion:
|
|
56
47
|
|
|
57
48
|
```python
|
|
58
|
-
hx
|
|
49
|
+
import hexconv as hx
|
|
50
|
+
|
|
51
|
+
hx.from_hex("dead beef").to_bytes()
|
|
59
52
|
# b'\xde\xad\xbe\xef'
|
|
60
53
|
|
|
61
|
-
hx.
|
|
62
|
-
# '
|
|
54
|
+
hx.from_hex("dead beef").bytes
|
|
55
|
+
# b'\xde\xad\xbe\xef'
|
|
63
56
|
|
|
64
|
-
hx.
|
|
65
|
-
# '
|
|
57
|
+
hx.from_bytes_array([0xde, 0xad, 0xbe, 0xef]).to_hex()
|
|
58
|
+
# 'deadbeef'
|
|
59
|
+
|
|
60
|
+
hx.from_bytes_array([0xde, 0xad, 0xbe, 0xef]).hex
|
|
61
|
+
# 'deadbeef'
|
|
62
|
+
|
|
63
|
+
hx.from_text("data").to_hex_array(prefix=True)
|
|
64
|
+
# ['0x64', '0x61', '0x74', '0x61']
|
|
65
|
+
|
|
66
|
+
hx.from_int(0xdeadbeef).to_bytes()
|
|
67
|
+
# b'\xde\xad\xbe\xef'
|
|
68
|
+
|
|
69
|
+
hx.from_int_array([0x1234, 0x5678], width=2).to_hex_array(width=2)
|
|
70
|
+
# ['1234', '5678']
|
|
66
71
|
```
|
|
67
72
|
|
|
68
73
|
Use `from_auto` when you want a quick best-effort parse:
|
|
@@ -78,19 +83,34 @@ hx.from_auto([0xde, 0xad, 0xbe, 0xef]).to(hx.Hex(prefix=True))
|
|
|
78
83
|
# '0xdeadbeef'
|
|
79
84
|
```
|
|
80
85
|
|
|
81
|
-
|
|
86
|
+
## Composable interface
|
|
87
|
+
|
|
88
|
+
`hexconv` is built around small format objects. A format can parse directly:
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
hx.Hex()("dead beef").bytes
|
|
92
|
+
# b'\xde\xad\xbe\xef'
|
|
93
|
+
|
|
94
|
+
hx.Text()("data").hex
|
|
95
|
+
# '64617461'
|
|
96
|
+
|
|
97
|
+
hx.Int(width=4, endian="little")(0x12345678).hex
|
|
98
|
+
# '78563412'
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Formats compose with `>>`:
|
|
82
102
|
|
|
83
103
|
```python
|
|
84
104
|
to_text = hx.HexArray() >> hx.Text()
|
|
85
|
-
to_text([
|
|
86
|
-
# '
|
|
105
|
+
to_text([0x48, 0x65, 0x6C, 0x6C, 0x6F])
|
|
106
|
+
# 'Hello'
|
|
87
107
|
|
|
88
108
|
to_hex = hx.Text() >> hx.Hex(prefix=True)
|
|
89
109
|
to_hex("data")
|
|
90
110
|
# '0x64617461'
|
|
91
111
|
```
|
|
92
112
|
|
|
93
|
-
|
|
113
|
+
Transforms sit between formats when data needs shaping:
|
|
94
114
|
|
|
95
115
|
```python
|
|
96
116
|
words = hx.Hex() >> hx.Chunk(2) >> hx.IntArray(width=2)
|
|
@@ -106,7 +126,7 @@ pad_hex("dead")
|
|
|
106
126
|
# '0000dead'
|
|
107
127
|
```
|
|
108
128
|
|
|
109
|
-
Use the builder form when
|
|
129
|
+
Use the builder form when named steps read better:
|
|
110
130
|
|
|
111
131
|
```python
|
|
112
132
|
conv = (
|
|
@@ -120,7 +140,28 @@ conv("12345678")
|
|
|
120
140
|
# ['0x1234', '0x5678']
|
|
121
141
|
```
|
|
122
142
|
|
|
123
|
-
##
|
|
143
|
+
## Configurable one-shot conversions
|
|
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
|
|
124
165
|
|
|
125
166
|
Text, bytes, and hex:
|
|
126
167
|
|
|
@@ -232,6 +273,13 @@ result.value.hex
|
|
|
232
273
|
# '05'
|
|
233
274
|
```
|
|
234
275
|
|
|
276
|
+
## Design priorities
|
|
277
|
+
|
|
278
|
+
- Easy: obvious conversions stay one-liners.
|
|
279
|
+
- Composable: reusable converters are just `format >> transform >> format`.
|
|
280
|
+
- Flexible: configure endianness, width, padding, grouping, text encoding, and base encodings where needed.
|
|
281
|
+
- Fast and lightweight: no runtime dependencies, bytes-native internals, and direct use of Python's optimized `bytes`, `int`, `base64`, and `struct` primitives.
|
|
282
|
+
|
|
235
283
|
## Format objects
|
|
236
284
|
|
|
237
285
|
Format objects are both parsers and pipeline endpoints.
|
|
@@ -45,6 +45,15 @@ 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"
|
|
49
|
+
assert hx.convert("data", hx.Text(), hx.Hex(prefix=True)) == "0x64617461"
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def test_convert_rejects_mixed_positional_and_keyword_formats():
|
|
53
|
+
with pytest.raises(hx.HexConvError, match="from_"):
|
|
54
|
+
hx.convert("data", hx.Text(), from_=hx.Text(), to=hx.Hex())
|
|
55
|
+
with pytest.raises(hx.HexConvError, match="to"):
|
|
56
|
+
hx.convert("data", hx.Text(), hx.Hex(), to=hx.Hex())
|
|
48
57
|
|
|
49
58
|
|
|
50
59
|
def test_converter_options():
|
|
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
|