weftcodec 1.2.0__py3-none-any.whl

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.
weftcodec/cli.py ADDED
@@ -0,0 +1,252 @@
1
+ """Command-line reader for WFT1 frames."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import json
7
+ import sys
8
+
9
+ from . import modes
10
+ from .dependency import DirectoryFrameSourceResolver, DirectoryResolver
11
+ from .errors import WeftError
12
+ from .frame import parse
13
+ from .identity import verify_frame
14
+ from .limits import Limits
15
+
16
+ EXIT_OK = 0
17
+ EXIT_FAILURE = 1
18
+ EXIT_USAGE = 2
19
+
20
+
21
+ def _resolver(args):
22
+ if getattr(args, "resolve", False):
23
+ source = getattr(args, "frame_source", None)
24
+ if not source:
25
+ raise SystemExit("--resolve requires --frame-source")
26
+ return DirectoryFrameSourceResolver(source, Limits())
27
+ if getattr(args, "deps", None):
28
+ return DirectoryResolver(args.deps)
29
+ return None
30
+
31
+
32
+ def _base_frame(args):
33
+ path = getattr(args, "base", None)
34
+ if not path:
35
+ return None
36
+ with open(path, "rb") as handle:
37
+ return handle.read()
38
+
39
+
40
+ def _print_error(exc: WeftError) -> None:
41
+ print("%s: %s" % (exc.error_class, exc.message), file=sys.stderr)
42
+
43
+
44
+ def _verify(args) -> int:
45
+ result = verify_frame(
46
+ args.file, _resolver(args), Limits(), _base_frame(args)
47
+ )
48
+ if result.ok:
49
+ if args.json:
50
+ print(json.dumps(result.to_dict(), sort_keys=True))
51
+ else:
52
+ print(
53
+ "OK mode=%s decoded_len=%d content_hash=%s chunks=%d dependencies=%d"
54
+ % (
55
+ result.mode,
56
+ result.decoded_len,
57
+ result.content_hash,
58
+ result.chunk_count,
59
+ result.dependency_count,
60
+ )
61
+ )
62
+ return EXIT_OK
63
+ if args.json:
64
+ print(json.dumps(result.to_dict(), sort_keys=True))
65
+ else:
66
+ print("%s: %s" % (result.error_class, result.error), file=sys.stderr)
67
+ return EXIT_FAILURE
68
+
69
+
70
+ def _decode(args) -> int:
71
+ try:
72
+ with open(args.file, "rb") as handle:
73
+ data = handle.read()
74
+ except OSError as exc:
75
+ print("Io: %s" % exc, file=sys.stderr)
76
+ return EXIT_FAILURE
77
+ try:
78
+ plaintext = modes.decode_bytes(
79
+ data, _resolver(args), Limits(), _base_frame(args)
80
+ )
81
+ except WeftError as exc:
82
+ _print_error(exc)
83
+ return EXIT_FAILURE
84
+ if args.output == "-":
85
+ sys.stdout.buffer.write(plaintext)
86
+ sys.stdout.buffer.flush()
87
+ return EXIT_OK
88
+ try:
89
+ with open(args.output, "wb") as handle:
90
+ handle.write(plaintext)
91
+ except OSError as exc:
92
+ print("Io: %s" % exc, file=sys.stderr)
93
+ return EXIT_FAILURE
94
+ return EXIT_OK
95
+
96
+
97
+ def _inspect_record(frame) -> dict:
98
+ header = frame.header
99
+ record = {
100
+ "ok": True,
101
+ "mode": header.mode_name,
102
+ "mode_value": header.mode,
103
+ "format_major": header.format_major,
104
+ "format_minor": header.format_minor,
105
+ "domain": header.domain,
106
+ "domain_name": "payload" if header.domain == 0 else "structured",
107
+ "flags": header.flag_names(),
108
+ "flags_value": header.flags,
109
+ "features": header.feature_names(),
110
+ "features_value": header.features,
111
+ "level": header.level,
112
+ "decoded_len": header.decoded_len,
113
+ "body_len": header.body_len,
114
+ "table_len": header.table_len,
115
+ "frame_len": len(frame.raw),
116
+ "chunk_count": header.chunk_count,
117
+ "dep_count": header.dep_count,
118
+ "dependency_count": header.dep_count,
119
+ "content_hash": header.content_hash.hex(),
120
+ "dependencies": [
121
+ {
122
+ "hash": dep.hash.hex(),
123
+ "decoded_len": dep.decoded_len,
124
+ "dep_domain": dep.dep_domain,
125
+ "dep_flags": dep.dep_flags,
126
+ "codec_hint": dep.codec_hint,
127
+ }
128
+ for dep in frame.dependencies
129
+ ],
130
+ "chunks": [
131
+ {
132
+ "encoded_off": chunk.encoded_off,
133
+ "encoded_len": chunk.encoded_len,
134
+ "decoded_len": chunk.decoded_len,
135
+ "hash": chunk.hash.hex(),
136
+ }
137
+ for chunk in frame.chunks
138
+ ],
139
+ }
140
+ limits = Limits()
141
+ try:
142
+ if header.mode == 6:
143
+ record["tensor"] = modes.tensor_metadata(frame, limits)
144
+ elif header.mode == 7:
145
+ record["tokens"] = modes.token_metadata(frame, limits)
146
+ elif header.mode == 8:
147
+ record["quantized_tensor"] = modes.quantized_tensor_metadata(frame, limits)
148
+ elif header.mode == 5:
149
+ from . import wcb
150
+
151
+ record["structured"] = _jsonable(wcb.decode(frame.body, limits))
152
+ except WeftError as exc:
153
+ record["descriptor_error"] = {
154
+ "error_class": exc.error_class,
155
+ "error": exc.message,
156
+ }
157
+ return record
158
+
159
+
160
+ def _jsonable(value):
161
+ from . import wcb
162
+
163
+ if value is None or isinstance(value, (bool, str, int, float)):
164
+ return value
165
+ if isinstance(value, (bytes, bytearray)):
166
+ return {"bytes_hex": bytes(value).hex()}
167
+ if isinstance(value, wcb.U64):
168
+ return {"u64": value.value}
169
+ if isinstance(value, wcb.I64):
170
+ return {"i64": value.value}
171
+ if isinstance(value, wcb.Timestamp):
172
+ return {"timestamp_nanos": value.nanos}
173
+ if isinstance(value, list):
174
+ return [_jsonable(item) for item in value]
175
+ if isinstance(value, dict):
176
+ return {key: _jsonable(item) for key, item in value.items()}
177
+ return repr(value)
178
+
179
+
180
+ def _inspect(args) -> int:
181
+ try:
182
+ with open(args.file, "rb") as handle:
183
+ data = handle.read()
184
+ except OSError as exc:
185
+ print(json.dumps({"ok": False, "error_class": "Io", "error": str(exc)}))
186
+ return EXIT_FAILURE
187
+ try:
188
+ frame = parse(data, Limits())
189
+ except WeftError as exc:
190
+ print(
191
+ json.dumps(
192
+ {"ok": False, "error_class": exc.error_class, "error": exc.message},
193
+ sort_keys=True,
194
+ )
195
+ )
196
+ return EXIT_FAILURE
197
+ print(json.dumps(_inspect_record(frame), sort_keys=True))
198
+ return EXIT_OK
199
+
200
+
201
+ def build_parser() -> argparse.ArgumentParser:
202
+ parser = argparse.ArgumentParser(
203
+ prog="python -m weftcodec",
204
+ description="Independent Python reader for Weft WFT1 frames and WCB.",
205
+ )
206
+ sub = parser.add_subparsers(dest="command", required=True)
207
+
208
+ verify = sub.add_parser("verify", help="validate a frame and every hash")
209
+ verify.add_argument("file")
210
+ verify.add_argument("--deps", help="directory of dependency files named by hex")
211
+ verify.add_argument(
212
+ "--base", help="base frame for WEIGHT_DELTA/SEMANTIC_DELTA/SPARSE_DELTA"
213
+ )
214
+ verify.add_argument(
215
+ "--resolve", action="store_true", help="resolve dependencies as frames"
216
+ )
217
+ verify.add_argument(
218
+ "--frame-source", dest="frame_source", help="directory of frames named by hex"
219
+ )
220
+ verify.add_argument("--json", action="store_true", help="emit a JSON result")
221
+ verify.set_defaults(func=_verify)
222
+
223
+ decode = sub.add_parser("decode", help="decode a frame to plaintext")
224
+ decode.add_argument("file")
225
+ decode.add_argument("output", help="output path, or - for stdout")
226
+ decode.add_argument("--deps", help="directory of dependency files named by hex")
227
+ decode.add_argument(
228
+ "--base", help="base frame for WEIGHT_DELTA/SEMANTIC_DELTA/SPARSE_DELTA"
229
+ )
230
+ decode.add_argument(
231
+ "--resolve", action="store_true", help="resolve dependencies as frames"
232
+ )
233
+ decode.add_argument(
234
+ "--frame-source", dest="frame_source", help="directory of frames named by hex"
235
+ )
236
+ decode.set_defaults(func=_decode)
237
+
238
+ inspect = sub.add_parser("inspect", help="emit frame metadata as JSON")
239
+ inspect.add_argument("file")
240
+ inspect.add_argument("--json", action="store_true", help=argparse.SUPPRESS)
241
+ inspect.set_defaults(func=_inspect)
242
+ return parser
243
+
244
+
245
+ def main(argv=None) -> int:
246
+ parser = build_parser()
247
+ args = parser.parse_args(argv)
248
+ return args.func(args)
249
+
250
+
251
+ if __name__ == "__main__": # pragma: no cover
252
+ raise SystemExit(main())
weftcodec/crc32c.py ADDED
@@ -0,0 +1,33 @@
1
+ """CRC-32C (Castagnoli), WEFTCODEC-FORMAT §1.
2
+
3
+ Polynomial 0x1EDC6F41, reflected input/output, init 0xFFFFFFFF, final XOR
4
+ 0xFFFFFFFF. Implemented locally so the reader has no extra dependency.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ _POLY = 0x82F63B78
10
+
11
+
12
+ def _make_table() -> "list[int]":
13
+ table = []
14
+ for index in range(256):
15
+ crc = index
16
+ for _ in range(8):
17
+ if crc & 1:
18
+ crc = (crc >> 1) ^ _POLY
19
+ else:
20
+ crc >>= 1
21
+ table.append(crc)
22
+ return table
23
+
24
+
25
+ _TABLE = _make_table()
26
+
27
+
28
+ def crc32c(data: bytes) -> int:
29
+ crc = 0xFFFFFFFF
30
+ table = _TABLE
31
+ for byte in data:
32
+ crc = table[(crc ^ byte) & 0xFF] ^ (crc >> 8)
33
+ return crc ^ 0xFFFFFFFF