mdrive4-json 0.0.4__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.
@@ -0,0 +1,55 @@
1
+ from .core import (
2
+ CalibrationRecord,
3
+ MDrive4JsonDataset,
4
+ MDrive4JsonWorkspaceManager,
5
+ NumpyCalibrationDataset,
6
+ NumpyExtrinsic,
7
+ NumpyIntrinsic,
8
+ build,
9
+ build_camera_sensor_payload,
10
+ create_camera_sensor,
11
+ create_sensor,
12
+ delete_sensor,
13
+ get_sensor,
14
+ load_dataset,
15
+ load_numpy_calibration,
16
+ list_records,
17
+ list_sensors,
18
+ parse,
19
+ read_order_manifest,
20
+ replace_sensors,
21
+ rpy_degrees_zyx_to_quaternion,
22
+ save_dataset,
23
+ update_sensor,
24
+ update_record,
25
+ validate_workspace,
26
+ )
27
+
28
+ __all__ = [
29
+ "CalibrationRecord",
30
+ "MDrive4JsonDataset",
31
+ "MDrive4JsonWorkspaceManager",
32
+ "NumpyCalibrationDataset",
33
+ "NumpyExtrinsic",
34
+ "NumpyIntrinsic",
35
+ "build",
36
+ "build_camera_sensor_payload",
37
+ "create_camera_sensor",
38
+ "create_sensor",
39
+ "delete_sensor",
40
+ "get_sensor",
41
+ "load_dataset",
42
+ "load_numpy_calibration",
43
+ "list_records",
44
+ "list_sensors",
45
+ "parse",
46
+ "read_order_manifest",
47
+ "replace_sensors",
48
+ "rpy_degrees_zyx_to_quaternion",
49
+ "save_dataset",
50
+ "update_sensor",
51
+ "update_record",
52
+ "validate_workspace",
53
+ ]
54
+
55
+ __version__ = "0.0.4"
mdrive4_json/cli.py ADDED
@@ -0,0 +1,134 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+ import sys
6
+ from typing import Any
7
+
8
+ from .core import (
9
+ build as api_build,
10
+ iter_summary_rows,
11
+ load_dataset,
12
+ parse as api_parse,
13
+ update_record,
14
+ validate_workspace as api_validate_workspace,
15
+ )
16
+
17
+
18
+ def main(argv: list[str] | None = None) -> int:
19
+ parser = _build_parser()
20
+ args = parser.parse_args(argv)
21
+ try:
22
+ args.func(args)
23
+ except ValueError as exc:
24
+ parser.exit(2, f"error: {exc}\n")
25
+ return 0
26
+
27
+
28
+ def _build_parser() -> argparse.ArgumentParser:
29
+ parser = argparse.ArgumentParser(
30
+ prog="mdrive4-json",
31
+ description="Read and edit mdrive4 JSON calibration files. Extrinsics are sensor->ego.",
32
+ )
33
+ subparsers = parser.add_subparsers(dest="command", required=True)
34
+
35
+ summary = subparsers.add_parser("summary", help="List sensors and sensor->ego poses")
36
+ summary.add_argument("input_dir")
37
+ summary.set_defaults(func=_cmd_summary)
38
+
39
+ show = subparsers.add_parser("show", help="Print one sensor JSON")
40
+ show.add_argument("input_dir")
41
+ show.add_argument("--sensor", required=True, help="sensor_id, e.g. camera1 or at128p_front")
42
+ show.set_defaults(func=_cmd_show)
43
+
44
+ edit = subparsers.add_parser("edit", help="Edit one sensor JSON")
45
+ edit.add_argument("input_dir")
46
+ edit.add_argument("--sensor", required=True, help="sensor_id, e.g. camera1 or at128p_front")
47
+ edit.add_argument("--set", dest="sets", action="append", required=True, metavar="KEY=VALUE")
48
+ edit.add_argument("--output-dir")
49
+ edit.add_argument("--inplace", action="store_true")
50
+ edit.add_argument("--allow-unknown", action="store_true")
51
+ edit.set_defaults(func=_cmd_edit)
52
+
53
+ parse = subparsers.add_parser("parse", help="Parse JSON directory into a YAML workspace")
54
+ parse.add_argument("input_dir")
55
+ parse.add_argument("-o", "--output", dest="workspace_dir", required=True)
56
+ parse.set_defaults(func=_cmd_parse)
57
+
58
+ build = subparsers.add_parser("build", help="Build JSON directory from a YAML workspace")
59
+ build.add_argument("-i", "--input", dest="workspace_dir", required=True)
60
+ build.add_argument("-o", "--output", dest="output_dir", required=True)
61
+ build.set_defaults(func=_cmd_build)
62
+
63
+ validate = subparsers.add_parser("validate", help="Validate a YAML workspace")
64
+ validate.add_argument("-i", "--input", dest="workspace_dir", required=True)
65
+ validate.set_defaults(func=_cmd_validate)
66
+ return parser
67
+
68
+
69
+ def _cmd_summary(args: argparse.Namespace) -> None:
70
+ dataset = load_dataset(args.input_dir)
71
+ print("sensor_id\tfile\tis_valid\tpos\troll\tpitch\tyaw")
72
+ for sensor_id, file_name, is_valid, pos, roll, pitch, yaw in iter_summary_rows(dataset.records):
73
+ pos_text = ",".join(f"{value:g}" for value in pos)
74
+ print(f"{sensor_id}\t{file_name}\t{is_valid}\t[{pos_text}]\t{roll:g}\t{pitch:g}\t{yaw:g}")
75
+
76
+
77
+ def _cmd_show(args: argparse.Namespace) -> None:
78
+ record = load_dataset(args.input_dir).get(args.sensor)
79
+ print(json.dumps(record.raw, ensure_ascii=False, indent=4))
80
+
81
+
82
+ def _cmd_edit(args: argparse.Namespace) -> None:
83
+ patch = _parse_sets(args.sets)
84
+ update_record(
85
+ args.input_dir,
86
+ args.sensor,
87
+ patch,
88
+ output_dir=args.output_dir,
89
+ inplace=args.inplace,
90
+ allow_unknown=args.allow_unknown,
91
+ )
92
+
93
+
94
+ def _cmd_parse(args: argparse.Namespace) -> None:
95
+ _, report = api_parse(args.input_dir, args.workspace_dir)
96
+ print(json.dumps(report, ensure_ascii=False, indent=2))
97
+
98
+
99
+ def _cmd_build(args: argparse.Namespace) -> None:
100
+ warnings = api_build(args.workspace_dir, args.output_dir)
101
+ if warnings:
102
+ print(json.dumps({"warnings": warnings}, ensure_ascii=False, indent=2))
103
+
104
+
105
+ def _cmd_validate(args: argparse.Namespace) -> None:
106
+ report = api_validate_workspace(args.workspace_dir)
107
+ print(json.dumps(report, ensure_ascii=False, indent=2))
108
+ if not report.get("valid", False):
109
+ raise ValueError(f"workspace is invalid: {report.get('errors')}")
110
+
111
+
112
+ def _parse_sets(items: list[str]) -> dict[str, Any]:
113
+ patch: dict[str, Any] = {}
114
+ for item in items:
115
+ if "=" not in item:
116
+ raise ValueError(f"--set must be KEY=VALUE, got {item!r}")
117
+ key, raw_value = item.split("=", 1)
118
+ key = key.strip()
119
+ if not key:
120
+ raise ValueError(f"--set key is empty in {item!r}")
121
+ patch[key] = _parse_value(raw_value)
122
+ return patch
123
+
124
+
125
+ def _parse_value(value: str) -> Any:
126
+ text = value.strip()
127
+ try:
128
+ return json.loads(text)
129
+ except json.JSONDecodeError:
130
+ return text
131
+
132
+
133
+ if __name__ == "__main__":
134
+ sys.exit(main())