brkraw 0.3.11__py3-none-any.whl → 0.5.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.
- brkraw/__init__.py +9 -3
- brkraw/apps/__init__.py +12 -0
- brkraw/apps/addon/__init__.py +30 -0
- brkraw/apps/addon/core.py +35 -0
- brkraw/apps/addon/dependencies.py +402 -0
- brkraw/apps/addon/installation.py +500 -0
- brkraw/apps/addon/io.py +21 -0
- brkraw/apps/hook/__init__.py +25 -0
- brkraw/apps/hook/core.py +636 -0
- brkraw/apps/loader/__init__.py +10 -0
- brkraw/apps/loader/core.py +622 -0
- brkraw/apps/loader/formatter.py +288 -0
- brkraw/apps/loader/helper.py +797 -0
- brkraw/apps/loader/info/__init__.py +11 -0
- brkraw/apps/loader/info/scan.py +85 -0
- brkraw/apps/loader/info/scan.yaml +90 -0
- brkraw/apps/loader/info/study.py +69 -0
- brkraw/apps/loader/info/study.yaml +156 -0
- brkraw/apps/loader/info/transform.py +92 -0
- brkraw/apps/loader/types.py +220 -0
- brkraw/cli/__init__.py +5 -0
- brkraw/cli/commands/__init__.py +2 -0
- brkraw/cli/commands/addon.py +327 -0
- brkraw/cli/commands/config.py +205 -0
- brkraw/cli/commands/convert.py +903 -0
- brkraw/cli/commands/hook.py +348 -0
- brkraw/cli/commands/info.py +74 -0
- brkraw/cli/commands/init.py +214 -0
- brkraw/cli/commands/params.py +106 -0
- brkraw/cli/commands/prune.py +288 -0
- brkraw/cli/commands/session.py +371 -0
- brkraw/cli/hook_args.py +80 -0
- brkraw/cli/main.py +83 -0
- brkraw/cli/utils.py +60 -0
- brkraw/core/__init__.py +13 -0
- brkraw/core/config.py +380 -0
- brkraw/core/entrypoints.py +25 -0
- brkraw/core/formatter.py +367 -0
- brkraw/core/fs.py +495 -0
- brkraw/core/jcamp.py +600 -0
- brkraw/core/layout.py +451 -0
- brkraw/core/parameters.py +781 -0
- brkraw/core/zip.py +1121 -0
- brkraw/dataclasses/__init__.py +14 -0
- brkraw/dataclasses/node.py +139 -0
- brkraw/dataclasses/reco.py +33 -0
- brkraw/dataclasses/scan.py +61 -0
- brkraw/dataclasses/study.py +131 -0
- brkraw/default/__init__.py +3 -0
- brkraw/default/pruner_specs/deid4share.yaml +42 -0
- brkraw/default/rules/00_default.yaml +4 -0
- brkraw/default/specs/metadata_dicom.yaml +236 -0
- brkraw/default/specs/metadata_transforms.py +92 -0
- brkraw/resolver/__init__.py +7 -0
- brkraw/resolver/affine.py +539 -0
- brkraw/resolver/datatype.py +69 -0
- brkraw/resolver/fid.py +90 -0
- brkraw/resolver/helpers.py +36 -0
- brkraw/resolver/image.py +188 -0
- brkraw/resolver/nifti.py +370 -0
- brkraw/resolver/shape.py +235 -0
- brkraw/schema/__init__.py +3 -0
- brkraw/schema/context_map.yaml +62 -0
- brkraw/schema/meta.yaml +57 -0
- brkraw/schema/niftiheader.yaml +95 -0
- brkraw/schema/pruner.yaml +55 -0
- brkraw/schema/remapper.yaml +128 -0
- brkraw/schema/rules.yaml +154 -0
- brkraw/specs/__init__.py +10 -0
- brkraw/specs/hook/__init__.py +12 -0
- brkraw/specs/hook/logic.py +31 -0
- brkraw/specs/hook/validator.py +22 -0
- brkraw/specs/meta/__init__.py +5 -0
- brkraw/specs/meta/validator.py +156 -0
- brkraw/specs/pruner/__init__.py +15 -0
- brkraw/specs/pruner/logic.py +361 -0
- brkraw/specs/pruner/validator.py +119 -0
- brkraw/specs/remapper/__init__.py +27 -0
- brkraw/specs/remapper/logic.py +924 -0
- brkraw/specs/remapper/validator.py +314 -0
- brkraw/specs/rules/__init__.py +6 -0
- brkraw/specs/rules/logic.py +263 -0
- brkraw/specs/rules/validator.py +103 -0
- brkraw-0.5.0.dist-info/METADATA +81 -0
- brkraw-0.5.0.dist-info/RECORD +88 -0
- {brkraw-0.3.11.dist-info → brkraw-0.5.0.dist-info}/WHEEL +1 -2
- brkraw-0.5.0.dist-info/entry_points.txt +13 -0
- brkraw/lib/__init__.py +0 -4
- brkraw/lib/backup.py +0 -641
- brkraw/lib/bids.py +0 -0
- brkraw/lib/errors.py +0 -125
- brkraw/lib/loader.py +0 -1220
- brkraw/lib/orient.py +0 -194
- brkraw/lib/parser.py +0 -48
- brkraw/lib/pvobj.py +0 -301
- brkraw/lib/reference.py +0 -245
- brkraw/lib/utils.py +0 -471
- brkraw/scripts/__init__.py +0 -0
- brkraw/scripts/brk_backup.py +0 -106
- brkraw/scripts/brkraw.py +0 -744
- brkraw/ui/__init__.py +0 -0
- brkraw/ui/config.py +0 -17
- brkraw/ui/main_win.py +0 -214
- brkraw/ui/previewer.py +0 -225
- brkraw/ui/scan_info.py +0 -72
- brkraw/ui/scan_list.py +0 -73
- brkraw/ui/subj_info.py +0 -128
- brkraw-0.3.11.dist-info/METADATA +0 -25
- brkraw-0.3.11.dist-info/RECORD +0 -28
- brkraw-0.3.11.dist-info/entry_points.txt +0 -3
- brkraw-0.3.11.dist-info/top_level.txt +0 -2
- tests/__init__.py +0 -0
- {brkraw-0.3.11.dist-info → brkraw-0.5.0.dist-info/licenses}/LICENSE +0 -0
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
"""Session command to manage BrkRaw environment defaults."""
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import os
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Iterable, List, Tuple
|
|
9
|
+
|
|
10
|
+
from brkraw.apps.loader import BrukerLoader
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _format_export(name: str, value: str) -> str:
|
|
14
|
+
escaped = value.replace("\"", "\\\"")
|
|
15
|
+
return f'export {name}="{escaped}"'
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _format_scan_ids(scan_ids: Iterable[int]) -> str:
|
|
19
|
+
return ",".join(str(sid) for sid in scan_ids)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _format_param_files(files: Iterable[str]) -> str:
|
|
23
|
+
return ",".join(str(item) for item in files)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def cmd_session(args: argparse.Namespace) -> int:
|
|
27
|
+
handler = getattr(args, "session_func", None)
|
|
28
|
+
if handler is None:
|
|
29
|
+
args.parser.print_help()
|
|
30
|
+
return 2
|
|
31
|
+
return handler(args)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def cmd_set(args: argparse.Namespace) -> int:
|
|
35
|
+
if (
|
|
36
|
+
not args.path
|
|
37
|
+
and not args.scan_id
|
|
38
|
+
and args.reco_id is None
|
|
39
|
+
and not args.param_key
|
|
40
|
+
and not args.param_file
|
|
41
|
+
and not args.convert_option
|
|
42
|
+
):
|
|
43
|
+
parser = getattr(args, "parser", None)
|
|
44
|
+
if parser is not None:
|
|
45
|
+
print(_format_short_help(parser))
|
|
46
|
+
print("\nTip: run `brkraw init --shell-rc ~/.zshrc` (or ~/.bashrc)")
|
|
47
|
+
print("Then use `brkraw-set ...` and `brkraw-unset` in your shell.")
|
|
48
|
+
print("You can still use `eval \"$(brkraw session set ...)\"` directly.")
|
|
49
|
+
return 2
|
|
50
|
+
lines: List[str] = []
|
|
51
|
+
if args.path:
|
|
52
|
+
path = Path(args.path).expanduser()
|
|
53
|
+
if not path.exists():
|
|
54
|
+
print(f"error: path not found: {path}")
|
|
55
|
+
return 2
|
|
56
|
+
try:
|
|
57
|
+
BrukerLoader(path)
|
|
58
|
+
except Exception as exc:
|
|
59
|
+
print(f"error: failed to load dataset at {path}: {exc}")
|
|
60
|
+
return 2
|
|
61
|
+
lines.append(_format_export("BRKRAW_PATH", str(path.resolve())))
|
|
62
|
+
if args.scan_id:
|
|
63
|
+
lines.append(_format_export("BRKRAW_SCAN_ID", _format_scan_ids(args.scan_id)))
|
|
64
|
+
if args.reco_id is not None:
|
|
65
|
+
lines.append(_format_export("BRKRAW_RECO_ID", str(args.reco_id)))
|
|
66
|
+
if args.param_key:
|
|
67
|
+
lines.append(_format_export("BRKRAW_PARAM_KEY", args.param_key))
|
|
68
|
+
if args.param_file:
|
|
69
|
+
lines.append(_format_export("BRKRAW_PARAM_FILE", _format_param_files(args.param_file)))
|
|
70
|
+
if args.convert_option:
|
|
71
|
+
convert_items: List[str] = []
|
|
72
|
+
for item in args.convert_option:
|
|
73
|
+
if isinstance(item, list):
|
|
74
|
+
convert_items.extend(item)
|
|
75
|
+
else:
|
|
76
|
+
convert_items.append(item)
|
|
77
|
+
for key, value in _parse_convert_options(convert_items):
|
|
78
|
+
lines.append(_format_export(f"BRKRAW_CONVERT_{key}", value))
|
|
79
|
+
if lines:
|
|
80
|
+
print("\n".join(lines))
|
|
81
|
+
return 0
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def cmd_unset(args: argparse.Namespace) -> int:
|
|
85
|
+
base_vars = [
|
|
86
|
+
"BRKRAW_PATH",
|
|
87
|
+
"BRKRAW_SCAN_ID",
|
|
88
|
+
"BRKRAW_RECO_ID",
|
|
89
|
+
"BRKRAW_PARAM_KEY",
|
|
90
|
+
"BRKRAW_PARAM_FILE",
|
|
91
|
+
]
|
|
92
|
+
convert_vars = [
|
|
93
|
+
"BRKRAW_CONVERT_OUTPUT",
|
|
94
|
+
"BRKRAW_CONVERT_PREFIX",
|
|
95
|
+
"BRKRAW_CONVERT_SCAN_ID",
|
|
96
|
+
"BRKRAW_CONVERT_RECO_ID",
|
|
97
|
+
"BRKRAW_CONVERT_SIDECAR",
|
|
98
|
+
"BRKRAW_CONVERT_CONTEXT_MAP",
|
|
99
|
+
"BRKRAW_CONVERT_SPACE",
|
|
100
|
+
"BRKRAW_CONVERT_COMPRESS",
|
|
101
|
+
"BRKRAW_CONVERT_FLIP_X",
|
|
102
|
+
"BRKRAW_CONVERT_FLATTEN_FG",
|
|
103
|
+
"BRKRAW_CONVERT_OVERRIDE_SUBJECT_TYPE",
|
|
104
|
+
"BRKRAW_CONVERT_OVERRIDE_SUBJECT_POSE",
|
|
105
|
+
"BRKRAW_CONVERT_XYZ_UNITS",
|
|
106
|
+
"BRKRAW_CONVERT_T_UNITS",
|
|
107
|
+
"BRKRAW_CONVERT_HEADER",
|
|
108
|
+
"BRKRAW_CONVERT_FORMAT",
|
|
109
|
+
]
|
|
110
|
+
targets: List[str] = []
|
|
111
|
+
if args.path:
|
|
112
|
+
targets.append("BRKRAW_PATH")
|
|
113
|
+
if args.scan_id:
|
|
114
|
+
targets.append("BRKRAW_SCAN_ID")
|
|
115
|
+
if args.reco_id:
|
|
116
|
+
targets.append("BRKRAW_RECO_ID")
|
|
117
|
+
if args.param_key:
|
|
118
|
+
targets.append("BRKRAW_PARAM_KEY")
|
|
119
|
+
if args.param_file:
|
|
120
|
+
targets.append("BRKRAW_PARAM_FILE")
|
|
121
|
+
|
|
122
|
+
if args.convert_option:
|
|
123
|
+
keys: List[str] = []
|
|
124
|
+
for item in args.convert_option:
|
|
125
|
+
if item is None or item == "*":
|
|
126
|
+
keys = ["*"]
|
|
127
|
+
break
|
|
128
|
+
keys.append(item)
|
|
129
|
+
if "*" in keys:
|
|
130
|
+
targets.extend(convert_vars)
|
|
131
|
+
else:
|
|
132
|
+
targets.extend(
|
|
133
|
+
[f"BRKRAW_CONVERT_{key.strip().upper().replace('-', '_')}" for key in keys]
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
if not targets:
|
|
137
|
+
targets = base_vars + convert_vars
|
|
138
|
+
print("unset " + " ".join(targets))
|
|
139
|
+
return 0
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def cmd_env(_: argparse.Namespace) -> int:
|
|
143
|
+
path = os.environ.get("BRKRAW_PATH")
|
|
144
|
+
scan_id = os.environ.get("BRKRAW_SCAN_ID")
|
|
145
|
+
reco_id = os.environ.get("BRKRAW_RECO_ID")
|
|
146
|
+
param_key = os.environ.get("BRKRAW_PARAM_KEY")
|
|
147
|
+
param_file = os.environ.get("BRKRAW_PARAM_FILE")
|
|
148
|
+
convert_output = os.environ.get("BRKRAW_CONVERT_OUTPUT")
|
|
149
|
+
convert_prefix = os.environ.get("BRKRAW_CONVERT_PREFIX")
|
|
150
|
+
convert_scan_id = os.environ.get("BRKRAW_CONVERT_SCAN_ID")
|
|
151
|
+
convert_reco_id = os.environ.get("BRKRAW_CONVERT_RECO_ID")
|
|
152
|
+
convert_sidecar = os.environ.get("BRKRAW_CONVERT_SIDECAR")
|
|
153
|
+
convert_context_map = os.environ.get("BRKRAW_CONVERT_CONTEXT_MAP")
|
|
154
|
+
convert_compress = os.environ.get("BRKRAW_CONVERT_COMPRESS")
|
|
155
|
+
convert_space = os.environ.get("BRKRAW_CONVERT_SPACE")
|
|
156
|
+
convert_flip_x = os.environ.get("BRKRAW_CONVERT_FLIP_X")
|
|
157
|
+
convert_flatten_fg = os.environ.get("BRKRAW_CONVERT_FLATTEN_FG")
|
|
158
|
+
convert_subject_type = os.environ.get("BRKRAW_CONVERT_OVERRIDE_SUBJECT_TYPE")
|
|
159
|
+
convert_subject_pose = os.environ.get("BRKRAW_CONVERT_OVERRIDE_SUBJECT_POSE")
|
|
160
|
+
convert_xyz_units = os.environ.get("BRKRAW_CONVERT_XYZ_UNITS")
|
|
161
|
+
convert_t_units = os.environ.get("BRKRAW_CONVERT_T_UNITS")
|
|
162
|
+
convert_header = os.environ.get("BRKRAW_CONVERT_HEADER")
|
|
163
|
+
convert_format = os.environ.get("BRKRAW_CONVERT_FORMAT")
|
|
164
|
+
if (
|
|
165
|
+
path is None
|
|
166
|
+
and scan_id is None
|
|
167
|
+
and reco_id is None
|
|
168
|
+
and param_key is None
|
|
169
|
+
and param_file is None
|
|
170
|
+
and convert_output is None
|
|
171
|
+
and convert_prefix is None
|
|
172
|
+
and convert_scan_id is None
|
|
173
|
+
and convert_reco_id is None
|
|
174
|
+
and convert_sidecar is None
|
|
175
|
+
and convert_context_map is None
|
|
176
|
+
and convert_compress is None
|
|
177
|
+
and convert_space is None
|
|
178
|
+
and convert_flip_x is None
|
|
179
|
+
and convert_flatten_fg is None
|
|
180
|
+
and convert_subject_type is None
|
|
181
|
+
and convert_subject_pose is None
|
|
182
|
+
and convert_xyz_units is None
|
|
183
|
+
and convert_t_units is None
|
|
184
|
+
and convert_header is None
|
|
185
|
+
and convert_format is None
|
|
186
|
+
):
|
|
187
|
+
print("(none)")
|
|
188
|
+
return 0
|
|
189
|
+
if path is not None:
|
|
190
|
+
print(f"BRKRAW_PATH={path}")
|
|
191
|
+
if scan_id is not None:
|
|
192
|
+
print(f"BRKRAW_SCAN_ID={scan_id}")
|
|
193
|
+
if reco_id is not None:
|
|
194
|
+
print(f"BRKRAW_RECO_ID={reco_id}")
|
|
195
|
+
if param_key is not None:
|
|
196
|
+
print(f"BRKRAW_PARAM_KEY={param_key}")
|
|
197
|
+
if param_file is not None:
|
|
198
|
+
print(f"BRKRAW_PARAM_FILE={param_file}")
|
|
199
|
+
if convert_output is not None:
|
|
200
|
+
print(f"BRKRAW_CONVERT_OUTPUT={convert_output}")
|
|
201
|
+
if convert_prefix is not None:
|
|
202
|
+
print(f"BRKRAW_CONVERT_PREFIX={convert_prefix}")
|
|
203
|
+
if convert_scan_id is not None:
|
|
204
|
+
print(f"BRKRAW_CONVERT_SCAN_ID={convert_scan_id}")
|
|
205
|
+
if convert_reco_id is not None:
|
|
206
|
+
print(f"BRKRAW_CONVERT_RECO_ID={convert_reco_id}")
|
|
207
|
+
if convert_sidecar is not None:
|
|
208
|
+
print(f"BRKRAW_CONVERT_SIDECAR={convert_sidecar}")
|
|
209
|
+
if convert_context_map is not None:
|
|
210
|
+
print(f"BRKRAW_CONVERT_CONTEXT_MAP={convert_context_map}")
|
|
211
|
+
if convert_space is not None:
|
|
212
|
+
print(f"BRKRAW_CONVERT_SPACE={convert_space}")
|
|
213
|
+
if convert_compress is not None:
|
|
214
|
+
print(f"BRKRAW_CONVERT_COMPRESS={convert_compress}")
|
|
215
|
+
if convert_flip_x is not None:
|
|
216
|
+
print(f"BRKRAW_CONVERT_FLIP_X={convert_flip_x}")
|
|
217
|
+
if convert_flatten_fg is not None:
|
|
218
|
+
print(f"BRKRAW_CONVERT_FLATTEN_FG={convert_flatten_fg}")
|
|
219
|
+
if convert_subject_type is not None:
|
|
220
|
+
print(f"BRKRAW_CONVERT_OVERRIDE_SUBJECT_TYPE={convert_subject_type}")
|
|
221
|
+
if convert_subject_pose is not None:
|
|
222
|
+
print(f"BRKRAW_CONVERT_OVERRIDE_SUBJECT_POSE={convert_subject_pose}")
|
|
223
|
+
if convert_xyz_units is not None:
|
|
224
|
+
print(f"BRKRAW_CONVERT_XYZ_UNITS={convert_xyz_units}")
|
|
225
|
+
if convert_t_units is not None:
|
|
226
|
+
print(f"BRKRAW_CONVERT_T_UNITS={convert_t_units}")
|
|
227
|
+
if convert_header is not None:
|
|
228
|
+
print(f"BRKRAW_CONVERT_HEADER={convert_header}")
|
|
229
|
+
if convert_format is not None:
|
|
230
|
+
print(f"BRKRAW_CONVERT_FORMAT={convert_format}")
|
|
231
|
+
return 0
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def _format_short_help(parser: argparse.ArgumentParser) -> str:
|
|
235
|
+
formatter = parser._get_formatter()
|
|
236
|
+
formatter.add_usage(parser.usage, parser._actions, parser._mutually_exclusive_groups)
|
|
237
|
+
for action_group in parser._action_groups:
|
|
238
|
+
formatter.start_section(action_group.title)
|
|
239
|
+
actions = [
|
|
240
|
+
action
|
|
241
|
+
for action in action_group._group_actions
|
|
242
|
+
if "-h" not in action.option_strings and "--help" not in action.option_strings
|
|
243
|
+
]
|
|
244
|
+
formatter.add_arguments(actions)
|
|
245
|
+
formatter.end_section()
|
|
246
|
+
return formatter.format_help()
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def _parse_convert_options(items: List[str]) -> List[Tuple[str, str]]:
|
|
250
|
+
pairs: List[Tuple[str, str]] = []
|
|
251
|
+
for item in items:
|
|
252
|
+
if "=" not in item:
|
|
253
|
+
raise ValueError(f"Invalid convert option (expected KEY=VALUE): {item}")
|
|
254
|
+
key, value = item.split("=", 1)
|
|
255
|
+
key = key.strip().upper().replace("-", "_")
|
|
256
|
+
if not key:
|
|
257
|
+
raise ValueError(f"Invalid convert option key in: {item}")
|
|
258
|
+
pairs.append((key, value.strip()))
|
|
259
|
+
return pairs
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def register(subparsers: argparse._SubParsersAction) -> None: # type: ignore[name-defined]
|
|
263
|
+
session_parser = subparsers.add_parser(
|
|
264
|
+
"session",
|
|
265
|
+
help="Manage BrkRaw environment defaults.",
|
|
266
|
+
)
|
|
267
|
+
session_parser.add_argument(
|
|
268
|
+
"--root",
|
|
269
|
+
help="Override config root directory (default: BRKRAW_CONFIG_HOME or ~/.brkraw).",
|
|
270
|
+
)
|
|
271
|
+
session_parser.set_defaults(func=cmd_session, parser=session_parser)
|
|
272
|
+
session_sub = session_parser.add_subparsers(dest="session_command")
|
|
273
|
+
|
|
274
|
+
set_parser = session_sub.add_parser(
|
|
275
|
+
"set",
|
|
276
|
+
help="Emit shell exports for BrkRaw environment defaults.",
|
|
277
|
+
)
|
|
278
|
+
set_parser.add_argument(
|
|
279
|
+
"-p",
|
|
280
|
+
"--path",
|
|
281
|
+
help="Default Bruker study path.",
|
|
282
|
+
)
|
|
283
|
+
set_parser.add_argument(
|
|
284
|
+
"-s",
|
|
285
|
+
"--scan-id",
|
|
286
|
+
nargs="*",
|
|
287
|
+
type=int,
|
|
288
|
+
help="Default scan id(s).",
|
|
289
|
+
)
|
|
290
|
+
set_parser.add_argument(
|
|
291
|
+
"-r",
|
|
292
|
+
"--reco-id",
|
|
293
|
+
type=int,
|
|
294
|
+
help="Default reco id.",
|
|
295
|
+
)
|
|
296
|
+
set_parser.add_argument(
|
|
297
|
+
"-k",
|
|
298
|
+
"--param-key",
|
|
299
|
+
help="Default parameter key for brkraw params.",
|
|
300
|
+
)
|
|
301
|
+
set_parser.add_argument(
|
|
302
|
+
"-f",
|
|
303
|
+
"--param-file",
|
|
304
|
+
nargs="*",
|
|
305
|
+
help="Default parameter file(s) for brkraw params.",
|
|
306
|
+
)
|
|
307
|
+
set_parser.add_argument(
|
|
308
|
+
"--convert-option",
|
|
309
|
+
action="append",
|
|
310
|
+
metavar="KEY=VALUE",
|
|
311
|
+
help=(
|
|
312
|
+
"Set BRKRAW_CONVERT_<OPTION> as KEY=VALUE (repeatable). "
|
|
313
|
+
"Keys: OUTPUT, PREFIX, SCAN_ID, RECO_ID, SIDECAR, CONTEXT_MAP, "
|
|
314
|
+
"COMPRESS, SPACE, FLIP_X, FLATTEN_FG, OVERRIDE_SUBJECT_TYPE, "
|
|
315
|
+
"OVERRIDE_SUBJECT_POSE, XYZ_UNITS, T_UNITS, HEADER, FORMAT."
|
|
316
|
+
),
|
|
317
|
+
)
|
|
318
|
+
set_parser.set_defaults(session_func=cmd_set, parser=set_parser)
|
|
319
|
+
|
|
320
|
+
unset_parser = session_sub.add_parser(
|
|
321
|
+
"unset",
|
|
322
|
+
help="Emit shell unset commands for BrkRaw environment defaults.",
|
|
323
|
+
)
|
|
324
|
+
unset_parser.add_argument(
|
|
325
|
+
"-p",
|
|
326
|
+
"--path",
|
|
327
|
+
action="store_true",
|
|
328
|
+
help="Unset BRKRAW_PATH.",
|
|
329
|
+
)
|
|
330
|
+
unset_parser.add_argument(
|
|
331
|
+
"-s",
|
|
332
|
+
"--scan-id",
|
|
333
|
+
action="store_true",
|
|
334
|
+
help="Unset BRKRAW_SCAN_ID.",
|
|
335
|
+
)
|
|
336
|
+
unset_parser.add_argument(
|
|
337
|
+
"-r",
|
|
338
|
+
"--reco-id",
|
|
339
|
+
action="store_true",
|
|
340
|
+
help="Unset BRKRAW_RECO_ID.",
|
|
341
|
+
)
|
|
342
|
+
unset_parser.add_argument(
|
|
343
|
+
"-k",
|
|
344
|
+
"--param-key",
|
|
345
|
+
action="store_true",
|
|
346
|
+
help="Unset BRKRAW_PARAM_KEY.",
|
|
347
|
+
)
|
|
348
|
+
unset_parser.add_argument(
|
|
349
|
+
"-f",
|
|
350
|
+
"--param-file",
|
|
351
|
+
action="store_true",
|
|
352
|
+
help="Unset BRKRAW_PARAM_FILE.",
|
|
353
|
+
)
|
|
354
|
+
unset_parser.add_argument(
|
|
355
|
+
"--convert-option",
|
|
356
|
+
nargs="?",
|
|
357
|
+
action="append",
|
|
358
|
+
const="*",
|
|
359
|
+
metavar="KEY",
|
|
360
|
+
help=(
|
|
361
|
+
"Unset BRKRAW_CONVERT_<OPTION> by KEY (repeatable). "
|
|
362
|
+
"Use without KEY to unset all convert variables."
|
|
363
|
+
),
|
|
364
|
+
)
|
|
365
|
+
unset_parser.set_defaults(session_func=cmd_unset)
|
|
366
|
+
|
|
367
|
+
env_parser = session_sub.add_parser(
|
|
368
|
+
"env",
|
|
369
|
+
help="Show current BrkRaw environment defaults.",
|
|
370
|
+
)
|
|
371
|
+
env_parser.set_defaults(session_func=cmd_env)
|
brkraw/cli/hook_args.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any, Dict, List, Mapping
|
|
6
|
+
|
|
7
|
+
import yaml
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def merge_hook_args(
|
|
11
|
+
base: Mapping[str, Mapping[str, Any]],
|
|
12
|
+
override: Mapping[str, Mapping[str, Any]],
|
|
13
|
+
) -> Dict[str, Dict[str, Any]]:
|
|
14
|
+
merged: Dict[str, Dict[str, Any]] = {}
|
|
15
|
+
for hook_name, values in base.items():
|
|
16
|
+
if not isinstance(hook_name, str) or not hook_name:
|
|
17
|
+
continue
|
|
18
|
+
if not isinstance(values, Mapping):
|
|
19
|
+
continue
|
|
20
|
+
merged[hook_name] = dict(values)
|
|
21
|
+
for hook_name, values in override.items():
|
|
22
|
+
if not isinstance(hook_name, str) or not hook_name:
|
|
23
|
+
continue
|
|
24
|
+
if not isinstance(values, Mapping):
|
|
25
|
+
continue
|
|
26
|
+
merged.setdefault(hook_name, {}).update(dict(values))
|
|
27
|
+
return merged
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def load_hook_args_yaml(paths: List[str]) -> Dict[str, Dict[str, Any]]:
|
|
31
|
+
"""Load hook args mapping from YAML files.
|
|
32
|
+
|
|
33
|
+
Supported YAML formats:
|
|
34
|
+
- `{hooks: {hook_name: {key: value}}}`
|
|
35
|
+
- `{hook_name: {key: value}}`
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
merged: Dict[str, Dict[str, Any]] = {}
|
|
39
|
+
|
|
40
|
+
def normalize_doc(doc: Any, *, source: str) -> Dict[str, Dict[str, Any]]:
|
|
41
|
+
if doc is None:
|
|
42
|
+
return {}
|
|
43
|
+
hooks_obj = doc.get("hooks") if isinstance(doc, Mapping) else None
|
|
44
|
+
if hooks_obj is None and isinstance(doc, Mapping):
|
|
45
|
+
hooks_obj = doc
|
|
46
|
+
if not isinstance(hooks_obj, Mapping):
|
|
47
|
+
raise ValueError(f"Invalid hook args YAML in {source!r}: expected mapping.")
|
|
48
|
+
|
|
49
|
+
out: Dict[str, Dict[str, Any]] = {}
|
|
50
|
+
for hook_name, values in hooks_obj.items():
|
|
51
|
+
if not isinstance(hook_name, str) or not hook_name.strip():
|
|
52
|
+
continue
|
|
53
|
+
if values is None:
|
|
54
|
+
continue
|
|
55
|
+
if not isinstance(values, Mapping):
|
|
56
|
+
raise ValueError(
|
|
57
|
+
f"Invalid hook args YAML in {source!r}: hook {hook_name!r} must map to a dict."
|
|
58
|
+
)
|
|
59
|
+
out[hook_name.strip()] = dict(values)
|
|
60
|
+
return out
|
|
61
|
+
|
|
62
|
+
for raw in paths:
|
|
63
|
+
source = raw.strip()
|
|
64
|
+
if not source:
|
|
65
|
+
continue
|
|
66
|
+
if source == "-":
|
|
67
|
+
doc = yaml.safe_load(sys.stdin.read())
|
|
68
|
+
else:
|
|
69
|
+
path = Path(source).expanduser()
|
|
70
|
+
if not path.exists():
|
|
71
|
+
raise ValueError(f"Hook args YAML not found: {source}")
|
|
72
|
+
doc = yaml.safe_load(path.read_text(encoding="utf-8"))
|
|
73
|
+
parsed = normalize_doc(doc, source=source)
|
|
74
|
+
merged = merge_hook_args(merged, parsed)
|
|
75
|
+
|
|
76
|
+
return merged
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
__all__ = ["load_hook_args_yaml", "merge_hook_args"]
|
|
80
|
+
|
brkraw/cli/main.py
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
from typing import Callable, List, Optional
|
|
5
|
+
from ..core.entrypoints import list_entry_points as _iter_entry_points
|
|
6
|
+
|
|
7
|
+
from brkraw import __version__
|
|
8
|
+
from brkraw.core import config as config_core
|
|
9
|
+
|
|
10
|
+
PLUGIN_GROUP = "brkraw.cli"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _register_entry_point_commands(
|
|
14
|
+
subparsers: argparse._SubParsersAction, # type: ignore[name-defined]
|
|
15
|
+
) -> None:
|
|
16
|
+
for ep in _iter_entry_points(PLUGIN_GROUP):
|
|
17
|
+
try:
|
|
18
|
+
register = ep.load()
|
|
19
|
+
except Exception as exc: # noqa: BLE001 - best-effort plugin load
|
|
20
|
+
print(f"warning: failed to load entry point {ep.name!r}: {exc}")
|
|
21
|
+
continue
|
|
22
|
+
if not callable(register):
|
|
23
|
+
raise TypeError("entry point must be callable (register(subparsers)).")
|
|
24
|
+
register(subparsers)
|
|
25
|
+
|
|
26
|
+
preferred = [
|
|
27
|
+
"init",
|
|
28
|
+
"config",
|
|
29
|
+
"session",
|
|
30
|
+
"info",
|
|
31
|
+
"params",
|
|
32
|
+
"convert",
|
|
33
|
+
"convert-batch",
|
|
34
|
+
"prune",
|
|
35
|
+
"addon",
|
|
36
|
+
"hook",
|
|
37
|
+
]
|
|
38
|
+
preferred_set = set(preferred)
|
|
39
|
+
ordered = [name for name in preferred if name in subparsers.choices]
|
|
40
|
+
ordered += [name for name in subparsers.choices if name not in preferred_set]
|
|
41
|
+
subparsers.choices = {name: subparsers.choices[name] for name in ordered}
|
|
42
|
+
choices_actions = getattr(subparsers, "_choices_actions", None)
|
|
43
|
+
if choices_actions:
|
|
44
|
+
action_map = {action.dest: action for action in choices_actions}
|
|
45
|
+
ordered_actions = [action_map[name] for name in ordered if name in action_map]
|
|
46
|
+
ordered_actions += [
|
|
47
|
+
action for action in choices_actions if action.dest not in ordered
|
|
48
|
+
]
|
|
49
|
+
subparsers._choices_actions = ordered_actions # type: ignore[attr-defined]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def main(argv: Optional[List[str]] = None) -> int:
|
|
53
|
+
config_core.configure_logging()
|
|
54
|
+
parser = argparse.ArgumentParser(
|
|
55
|
+
prog="brkraw",
|
|
56
|
+
description="BrkRaw command-line interface.",
|
|
57
|
+
)
|
|
58
|
+
parser.add_argument(
|
|
59
|
+
"-v", "--version", action="version", version="%(prog)s v{}".format(__version__)
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
subparsers = parser.add_subparsers(
|
|
63
|
+
title="Sub-commands",
|
|
64
|
+
description=(
|
|
65
|
+
"Choose one of the sub-commands below. For details on a specific "
|
|
66
|
+
"command, run: brkraw <command> -h."
|
|
67
|
+
),
|
|
68
|
+
dest="command",
|
|
69
|
+
metavar="command",
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
_register_entry_point_commands(subparsers)
|
|
73
|
+
|
|
74
|
+
args = parser.parse_args(argv)
|
|
75
|
+
if not hasattr(args, "func"):
|
|
76
|
+
parser.print_help()
|
|
77
|
+
return 2
|
|
78
|
+
func: Callable[[argparse.Namespace], int] = args.func
|
|
79
|
+
return func(args)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
if __name__ == "__main__":
|
|
83
|
+
raise SystemExit(main())
|
brkraw/cli/utils.py
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""Formatting helpers for CLI-style output.
|
|
2
|
+
|
|
3
|
+
Last updated: 2025-12-30
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import itertools
|
|
9
|
+
import logging
|
|
10
|
+
import threading
|
|
11
|
+
import time
|
|
12
|
+
from contextlib import contextmanager
|
|
13
|
+
from typing import Iterator, List
|
|
14
|
+
|
|
15
|
+
from brkraw.apps.loader import BrukerLoader
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger("brkraw")
|
|
18
|
+
|
|
19
|
+
@contextmanager
|
|
20
|
+
def spinner(prefix: str = "Loading") -> Iterator[None]:
|
|
21
|
+
"""Display a simple CLI spinner while a block runs.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
prefix: Text shown before the spinner glyph.
|
|
25
|
+
|
|
26
|
+
Yields:
|
|
27
|
+
None.
|
|
28
|
+
"""
|
|
29
|
+
if logger.isEnabledFor(logging.DEBUG):
|
|
30
|
+
yield
|
|
31
|
+
return
|
|
32
|
+
|
|
33
|
+
stop_event = threading.Event()
|
|
34
|
+
seq = itertools.cycle("|/-\\")
|
|
35
|
+
|
|
36
|
+
def run() -> None:
|
|
37
|
+
while not stop_event.is_set():
|
|
38
|
+
print(f"\r{prefix} {next(seq)}", end="", flush=True)
|
|
39
|
+
time.sleep(0.08)
|
|
40
|
+
|
|
41
|
+
thread = threading.Thread(target=run, daemon=True)
|
|
42
|
+
thread.start()
|
|
43
|
+
try:
|
|
44
|
+
yield
|
|
45
|
+
finally:
|
|
46
|
+
stop_event.set()
|
|
47
|
+
thread.join()
|
|
48
|
+
print("\r" + " " * (len(prefix) + 2) + "\r", end="", flush=True)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def load(path, *, prefix: str = "Loading") -> BrukerLoader:
|
|
52
|
+
"""Load a Bruker dataset with a CLI spinner."""
|
|
53
|
+
with spinner(prefix):
|
|
54
|
+
return BrukerLoader(path)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
__all__ = ["spinner", "load"]
|
|
58
|
+
|
|
59
|
+
def __dir__() -> List[str]:
|
|
60
|
+
return sorted(__all__)
|