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.
Files changed (113) hide show
  1. brkraw/__init__.py +9 -3
  2. brkraw/apps/__init__.py +12 -0
  3. brkraw/apps/addon/__init__.py +30 -0
  4. brkraw/apps/addon/core.py +35 -0
  5. brkraw/apps/addon/dependencies.py +402 -0
  6. brkraw/apps/addon/installation.py +500 -0
  7. brkraw/apps/addon/io.py +21 -0
  8. brkraw/apps/hook/__init__.py +25 -0
  9. brkraw/apps/hook/core.py +636 -0
  10. brkraw/apps/loader/__init__.py +10 -0
  11. brkraw/apps/loader/core.py +622 -0
  12. brkraw/apps/loader/formatter.py +288 -0
  13. brkraw/apps/loader/helper.py +797 -0
  14. brkraw/apps/loader/info/__init__.py +11 -0
  15. brkraw/apps/loader/info/scan.py +85 -0
  16. brkraw/apps/loader/info/scan.yaml +90 -0
  17. brkraw/apps/loader/info/study.py +69 -0
  18. brkraw/apps/loader/info/study.yaml +156 -0
  19. brkraw/apps/loader/info/transform.py +92 -0
  20. brkraw/apps/loader/types.py +220 -0
  21. brkraw/cli/__init__.py +5 -0
  22. brkraw/cli/commands/__init__.py +2 -0
  23. brkraw/cli/commands/addon.py +327 -0
  24. brkraw/cli/commands/config.py +205 -0
  25. brkraw/cli/commands/convert.py +903 -0
  26. brkraw/cli/commands/hook.py +348 -0
  27. brkraw/cli/commands/info.py +74 -0
  28. brkraw/cli/commands/init.py +214 -0
  29. brkraw/cli/commands/params.py +106 -0
  30. brkraw/cli/commands/prune.py +288 -0
  31. brkraw/cli/commands/session.py +371 -0
  32. brkraw/cli/hook_args.py +80 -0
  33. brkraw/cli/main.py +83 -0
  34. brkraw/cli/utils.py +60 -0
  35. brkraw/core/__init__.py +13 -0
  36. brkraw/core/config.py +380 -0
  37. brkraw/core/entrypoints.py +25 -0
  38. brkraw/core/formatter.py +367 -0
  39. brkraw/core/fs.py +495 -0
  40. brkraw/core/jcamp.py +600 -0
  41. brkraw/core/layout.py +451 -0
  42. brkraw/core/parameters.py +781 -0
  43. brkraw/core/zip.py +1121 -0
  44. brkraw/dataclasses/__init__.py +14 -0
  45. brkraw/dataclasses/node.py +139 -0
  46. brkraw/dataclasses/reco.py +33 -0
  47. brkraw/dataclasses/scan.py +61 -0
  48. brkraw/dataclasses/study.py +131 -0
  49. brkraw/default/__init__.py +3 -0
  50. brkraw/default/pruner_specs/deid4share.yaml +42 -0
  51. brkraw/default/rules/00_default.yaml +4 -0
  52. brkraw/default/specs/metadata_dicom.yaml +236 -0
  53. brkraw/default/specs/metadata_transforms.py +92 -0
  54. brkraw/resolver/__init__.py +7 -0
  55. brkraw/resolver/affine.py +539 -0
  56. brkraw/resolver/datatype.py +69 -0
  57. brkraw/resolver/fid.py +90 -0
  58. brkraw/resolver/helpers.py +36 -0
  59. brkraw/resolver/image.py +188 -0
  60. brkraw/resolver/nifti.py +370 -0
  61. brkraw/resolver/shape.py +235 -0
  62. brkraw/schema/__init__.py +3 -0
  63. brkraw/schema/context_map.yaml +62 -0
  64. brkraw/schema/meta.yaml +57 -0
  65. brkraw/schema/niftiheader.yaml +95 -0
  66. brkraw/schema/pruner.yaml +55 -0
  67. brkraw/schema/remapper.yaml +128 -0
  68. brkraw/schema/rules.yaml +154 -0
  69. brkraw/specs/__init__.py +10 -0
  70. brkraw/specs/hook/__init__.py +12 -0
  71. brkraw/specs/hook/logic.py +31 -0
  72. brkraw/specs/hook/validator.py +22 -0
  73. brkraw/specs/meta/__init__.py +5 -0
  74. brkraw/specs/meta/validator.py +156 -0
  75. brkraw/specs/pruner/__init__.py +15 -0
  76. brkraw/specs/pruner/logic.py +361 -0
  77. brkraw/specs/pruner/validator.py +119 -0
  78. brkraw/specs/remapper/__init__.py +27 -0
  79. brkraw/specs/remapper/logic.py +924 -0
  80. brkraw/specs/remapper/validator.py +314 -0
  81. brkraw/specs/rules/__init__.py +6 -0
  82. brkraw/specs/rules/logic.py +263 -0
  83. brkraw/specs/rules/validator.py +103 -0
  84. brkraw-0.5.0.dist-info/METADATA +81 -0
  85. brkraw-0.5.0.dist-info/RECORD +88 -0
  86. {brkraw-0.3.11.dist-info → brkraw-0.5.0.dist-info}/WHEEL +1 -2
  87. brkraw-0.5.0.dist-info/entry_points.txt +13 -0
  88. brkraw/lib/__init__.py +0 -4
  89. brkraw/lib/backup.py +0 -641
  90. brkraw/lib/bids.py +0 -0
  91. brkraw/lib/errors.py +0 -125
  92. brkraw/lib/loader.py +0 -1220
  93. brkraw/lib/orient.py +0 -194
  94. brkraw/lib/parser.py +0 -48
  95. brkraw/lib/pvobj.py +0 -301
  96. brkraw/lib/reference.py +0 -245
  97. brkraw/lib/utils.py +0 -471
  98. brkraw/scripts/__init__.py +0 -0
  99. brkraw/scripts/brk_backup.py +0 -106
  100. brkraw/scripts/brkraw.py +0 -744
  101. brkraw/ui/__init__.py +0 -0
  102. brkraw/ui/config.py +0 -17
  103. brkraw/ui/main_win.py +0 -214
  104. brkraw/ui/previewer.py +0 -225
  105. brkraw/ui/scan_info.py +0 -72
  106. brkraw/ui/scan_list.py +0 -73
  107. brkraw/ui/subj_info.py +0 -128
  108. brkraw-0.3.11.dist-info/METADATA +0 -25
  109. brkraw-0.3.11.dist-info/RECORD +0 -28
  110. brkraw-0.3.11.dist-info/entry_points.txt +0 -3
  111. brkraw-0.3.11.dist-info/top_level.txt +0 -2
  112. tests/__init__.py +0 -0
  113. {brkraw-0.3.11.dist-info → brkraw-0.5.0.dist-info/licenses}/LICENSE +0 -0
@@ -0,0 +1,205 @@
1
+ from __future__ import annotations
2
+ from typing import List, Tuple, Optional
3
+
4
+ import argparse
5
+ import logging
6
+ from pathlib import Path
7
+
8
+ import yaml
9
+ import shlex
10
+ import subprocess
11
+
12
+ from brkraw.core import config as config_core
13
+
14
+ logger = logging.getLogger("brkraw")
15
+
16
+
17
+ def cmd_config(args: argparse.Namespace) -> int:
18
+ handler = getattr(args, "config_func", None)
19
+ if handler is None:
20
+ args.parser.print_help()
21
+ return 2
22
+ return handler(args)
23
+
24
+
25
+ def cmd_init(args: argparse.Namespace) -> int:
26
+ config_core.init(
27
+ root=args.root,
28
+ create_config=not args.no_config,
29
+ exist_ok=not args.no_exist_ok,
30
+ )
31
+ return 0
32
+
33
+
34
+ def cmd_show(args: argparse.Namespace) -> int:
35
+ config = config_core.resolve_config(root=args.root)
36
+ if not config:
37
+ print("config.yaml: <empty>")
38
+ return 0
39
+ ordered = _order_config(config)
40
+ text = yaml.safe_dump(ordered, sort_keys=False)
41
+ print(text.rstrip())
42
+ return 0
43
+
44
+
45
+ def cmd_path(args: argparse.Namespace) -> int:
46
+ path = config_core.get_path(args.name, root=args.root)
47
+ print(path)
48
+ return 0
49
+
50
+
51
+ def cmd_set(args: argparse.Namespace) -> int:
52
+ config = config_core.load(root=args.root) or {}
53
+ key, value = _parse_set_kv(args.key, args.value)
54
+ if "." in key:
55
+ _set_nested(config, key.split("."), value)
56
+ else:
57
+ config[key] = value
58
+ config_core.write_config(config, root=args.root)
59
+ return 0
60
+
61
+
62
+ def cmd_unset(args: argparse.Namespace) -> int:
63
+ config = config_core.load(root=args.root) or {}
64
+ if "." in args.key:
65
+ _unset_nested(config, args.key.split("."))
66
+ elif args.key in config:
67
+ config.pop(args.key)
68
+ config_core.write_config(config, root=args.root)
69
+ return 0
70
+
71
+
72
+ def cmd_reset(args: argparse.Namespace) -> int:
73
+ paths = config_core.paths(root=args.root)
74
+ if paths.config_file.exists() and not args.yes:
75
+ prompt = f"Reset config.yaml at {paths.config_file}? [y/N]: "
76
+ reply = input(prompt).strip().lower()
77
+ if reply not in {"y", "yes"}:
78
+ return 1
79
+ config_core.reset_config(root=args.root)
80
+ return 0
81
+
82
+
83
+ def cmd_edit(args: argparse.Namespace) -> int:
84
+ editor = config_core.resolve_editor_binary(root=args.root)
85
+ if not editor:
86
+ logger.error("No editor configured. Set editor or $EDITOR.")
87
+ return 2
88
+ paths = config_core.paths(root=args.root)
89
+ if not paths.config_file.exists():
90
+ config_core.reset_config(root=args.root)
91
+ cmd = shlex.split(editor) + [str(paths.config_file)]
92
+ return subprocess.call(cmd)
93
+
94
+
95
+ def _parse_set_kv(key: str, value: Optional[str]) -> Tuple[str, object]:
96
+ if value is None and "=" in key:
97
+ key, value = key.split("=", 1)
98
+ if value is None:
99
+ raise ValueError("config set requires KEY VALUE or KEY=VALUE.")
100
+ return key, yaml.safe_load(value)
101
+
102
+
103
+ def _format_config_value(value: object) -> str:
104
+ if isinstance(value, (dict, list, tuple)):
105
+ return yaml.safe_dump(value, default_flow_style=True).strip()
106
+ if value is None:
107
+ return "null"
108
+ if isinstance(value, bool):
109
+ return "true" if value else "false"
110
+ return str(value)
111
+
112
+
113
+ def _order_config(config: dict) -> dict:
114
+ order = ["config_version", "editor", "logging", "output"]
115
+ ordered = {key: config[key] for key in order if key in config}
116
+ for key in sorted(k for k in config.keys() if k not in ordered):
117
+ ordered[key] = config[key]
118
+ return ordered
119
+
120
+
121
+ def _set_nested(data: dict, parts: List[str], value: object) -> None:
122
+ current = data
123
+ for part in parts[:-1]:
124
+ node = current.get(part)
125
+ if not isinstance(node, dict):
126
+ node = {}
127
+ current[part] = node
128
+ current = node
129
+ current[parts[-1]] = value
130
+
131
+
132
+ def _unset_nested(data: dict, parts: List[str]) -> None:
133
+ current = data
134
+ stack = []
135
+ for part in parts[:-1]:
136
+ node = current.get(part)
137
+ if not isinstance(node, dict):
138
+ return
139
+ stack.append((current, part))
140
+ current = node
141
+ if parts[-1] in current:
142
+ current.pop(parts[-1])
143
+ for parent, key in reversed(stack):
144
+ child = parent.get(key)
145
+ if isinstance(child, dict) and not child:
146
+ parent.pop(key)
147
+ else:
148
+ break
149
+
150
+
151
+ def register(subparsers: argparse._SubParsersAction) -> None: # type: ignore[name-defined]
152
+ config_parser = subparsers.add_parser(
153
+ "config",
154
+ help="Manage brkraw config locations.",
155
+ )
156
+ config_parser.add_argument(
157
+ "--root",
158
+ help="Override config root directory (default: BRKRAW_CONFIG_HOME or ~/.brkraw).",
159
+ )
160
+ config_parser.set_defaults(func=cmd_config, parser=config_parser)
161
+ config_sub = config_parser.add_subparsers(dest="config_command")
162
+
163
+ init_parser = config_sub.add_parser("init", help="Create the config folders.")
164
+ init_parser.add_argument(
165
+ "--no-config",
166
+ action="store_true",
167
+ help="Do not create config.yaml.",
168
+ )
169
+ init_parser.add_argument(
170
+ "--no-exist-ok",
171
+ action="store_true",
172
+ help="Fail if the root directory already exists.",
173
+ )
174
+ init_parser.set_defaults(config_func=cmd_init)
175
+
176
+ show_parser = config_sub.add_parser("show", help="Print resolved config values.")
177
+ show_parser.set_defaults(config_func=cmd_show)
178
+
179
+ path_parser = config_sub.add_parser("path", help="Print a specific config path.")
180
+ path_parser.add_argument(
181
+ "name",
182
+ choices=["root", "config", "rules", "specs", "transforms"],
183
+ help="Path key to print.",
184
+ )
185
+ path_parser.set_defaults(config_func=cmd_path)
186
+
187
+ edit_parser = config_sub.add_parser("edit", help="Edit config.yaml in an editor.")
188
+ edit_parser.set_defaults(config_func=cmd_edit)
189
+
190
+ set_parser = config_sub.add_parser("set", help="Set a config key.")
191
+ set_parser.add_argument("key", help="Config key to set (or KEY=VALUE).")
192
+ set_parser.add_argument("value", nargs="?", help="Value to set.")
193
+ set_parser.set_defaults(config_func=cmd_set)
194
+
195
+ unset_parser = config_sub.add_parser("unset", help="Unset a config key.")
196
+ unset_parser.add_argument("key", help="Config key to remove.")
197
+ unset_parser.set_defaults(config_func=cmd_unset)
198
+
199
+ reset_parser = config_sub.add_parser("reset", help="Reset config.yaml to defaults.")
200
+ reset_parser.add_argument(
201
+ "--yes",
202
+ action="store_true",
203
+ help="Do not prompt for confirmation.",
204
+ )
205
+ reset_parser.set_defaults(config_func=cmd_reset)