brkraw 0.5.0rc1__tar.gz → 0.5.1__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.
Files changed (206) hide show
  1. brkraw-0.5.1/.github/copilot-instructions.md +10 -0
  2. {brkraw-0.5.0rc1 → brkraw-0.5.1}/.github/workflows/publish.yml +2 -31
  3. {brkraw-0.5.0rc1 → brkraw-0.5.1}/.github/workflows/release.yml +1 -1
  4. brkraw-0.5.1/.github/workflows/release_on_merge.yml +54 -0
  5. {brkraw-0.5.0rc1 → brkraw-0.5.1}/.gitignore +1 -0
  6. brkraw-0.5.1/.markdownlint.yaml +6 -0
  7. brkraw-0.5.1/AGENTS.md +22 -0
  8. brkraw-0.5.1/CITATION.cff +49 -0
  9. {brkraw-0.5.0rc1 → brkraw-0.5.1}/PKG-INFO +31 -4
  10. brkraw-0.5.1/README.md +43 -0
  11. brkraw-0.5.1/RELEASE_NOTES.md +13 -0
  12. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/__init__.py +1 -1
  13. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/apps/hook/core.py +58 -10
  14. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/apps/loader/core.py +5 -1
  15. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/apps/loader/helper.py +155 -14
  16. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/apps/loader/info/scan.py +18 -5
  17. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/apps/loader/types.py +6 -1
  18. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/cli/commands/convert.py +201 -79
  19. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/cli/commands/hook.py +146 -4
  20. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/cli/commands/session.py +6 -1
  21. brkraw-0.5.1/brkraw/cli/hook_args.py +80 -0
  22. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/core/config.py +8 -0
  23. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/core/layout.py +56 -11
  24. brkraw-0.5.1/brkraw/default/rules/00_default.yaml +4 -0
  25. brkraw-0.5.1/brkraw/default/specs/metadata_dicom.yaml +236 -0
  26. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/default/specs/metadata_transforms.py +18 -0
  27. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/resolver/affine.py +56 -32
  28. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/schema/context_map.yaml +5 -0
  29. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/schema/remapper.yaml +6 -0
  30. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/specs/__init__.py +2 -2
  31. {brkraw-0.5.0rc1/brkraw/specs/converter → brkraw-0.5.1/brkraw/specs/hook}/logic.py +1 -0
  32. {brkraw-0.5.0rc1/brkraw/specs/converter → brkraw-0.5.1/brkraw/specs/hook}/validator.py +1 -0
  33. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/specs/remapper/logic.py +83 -16
  34. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/specs/remapper/validator.py +21 -5
  35. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/api/convert.md +17 -0
  36. brkraw-0.5.1/docs/api/data-access.md +145 -0
  37. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/api/hook.md +0 -1
  38. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/api/layout.md +27 -0
  39. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/api/overview.md +3 -0
  40. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/cli/addon.md +15 -8
  41. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/cli/convert.md +49 -2
  42. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/cli/hook.md +23 -4
  43. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/cli/index.md +2 -2
  44. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/cli/info.md +1 -78
  45. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/cli/session.md +1 -1
  46. brkraw-0.5.1/docs/dev/cli-extensions.md +59 -0
  47. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/dev/contributing.md +12 -36
  48. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/dev/contributors.md +4 -4
  49. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/dev/core-vs-addon.md +3 -3
  50. brkraw-0.5.1/docs/dev/documentation.md +58 -0
  51. brkraw-0.5.1/docs/dev/hook-packages.md +199 -0
  52. brkraw-0.5.1/docs/dev/roadmap.md +492 -0
  53. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/getting-started/api.md +3 -0
  54. brkraw-0.5.1/docs/getting-started/backup.md +10 -0
  55. brkraw-0.5.1/docs/getting-started/bids.md +19 -0
  56. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/getting-started/cli.md +1 -0
  57. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/getting-started/hooks.md +16 -0
  58. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/getting-started/index.md +9 -0
  59. brkraw-0.5.1/docs/getting-started/mrs.md +10 -0
  60. brkraw-0.5.1/docs/getting-started/viewer.md +15 -0
  61. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/index.md +2 -2
  62. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/reference/addons-and-plugins.md +4 -0
  63. brkraw-0.5.1/docs/reference/cli-extensions.md +23 -0
  64. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/reference/context-map.md +113 -2
  65. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/reference/extensibility.md +9 -15
  66. brkraw-0.5.1/docs/reference/hook-packages.md +18 -0
  67. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/reference/layout.md +16 -0
  68. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/reference/rules.md +48 -1
  69. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/reference/specs.md +89 -21
  70. {brkraw-0.5.0rc1 → brkraw-0.5.1}/mkdocs.yml +10 -2
  71. {brkraw-0.5.0rc1 → brkraw-0.5.1}/pyproject.toml +1 -1
  72. brkraw-0.5.1/scripts/cff_to_biblatex.py +179 -0
  73. brkraw-0.5.1/scripts/release_notes.py +99 -0
  74. brkraw-0.5.1/scripts/release_pr.py +491 -0
  75. {brkraw-0.5.0rc1 → brkraw-0.5.1}/scripts/release_prep.py +28 -0
  76. {brkraw-0.5.0rc1 → brkraw-0.5.1}/scripts/update_contributors.py +59 -9
  77. brkraw-0.5.1/scripts/update_readme_bibtex.py +61 -0
  78. brkraw-0.5.1/scripts/verify_release_version.py +48 -0
  79. {brkraw-0.5.0rc1 → brkraw-0.5.1}/tests/conftest.py +4 -1
  80. {brkraw-0.5.0rc1/tests/test_core → brkraw-0.5.1/tests/test_01_core}/test_fs.py +1 -1
  81. {brkraw-0.5.0rc1/tests/test_core → brkraw-0.5.1/tests/test_01_core}/test_jcamp.py +1 -1
  82. {brkraw-0.5.0rc1/tests/test_core → brkraw-0.5.1/tests/test_01_core}/test_parameters.py +1 -1
  83. {brkraw-0.5.0rc1/tests/test_core → brkraw-0.5.1/tests/test_01_core}/test_zip.py +1 -1
  84. brkraw-0.5.0rc1/tests/test_dataclasses.py → brkraw-0.5.1/tests/test_02_dataclasses/test_dir-vs-zipped.py +1 -1
  85. brkraw-0.5.1/tests/test_03_resolver/test_affine.py +32 -0
  86. brkraw-0.5.1/tests/test_04_specs/test_context_map_cases.py +61 -0
  87. brkraw-0.5.1/tests/test_04_specs/test_remapper.py +92 -0
  88. brkraw-0.5.1/tests/test_apps/test_affine_post_transform.py +34 -0
  89. brkraw-0.5.1/tests/test_apps/test_loader_info_missing_visu_pars.py +54 -0
  90. brkraw-0.5.1/tests/test_cli/test_hook_args_yaml.py +74 -0
  91. brkraw-0.5.1/tests/test_cli/test_hook_preset.py +30 -0
  92. brkraw-0.5.1/tests/test_scripts/test_update_contributors.py +43 -0
  93. brkraw-0.5.0rc1/.markdownlint.yaml +0 -4
  94. brkraw-0.5.0rc1/README.md +0 -16
  95. brkraw-0.5.0rc1/RELEASE_NOTES.md +0 -10
  96. brkraw-0.5.0rc1/brkraw/default/rules/10-metadata.yaml +0 -42
  97. brkraw-0.5.0rc1/brkraw/default/rules/20-mrs.yaml +0 -14
  98. brkraw-0.5.0rc1/brkraw/default/specs/metadata_anat.yaml +0 -54
  99. brkraw-0.5.0rc1/brkraw/default/specs/metadata_common.yaml +0 -129
  100. brkraw-0.5.0rc1/brkraw/default/specs/metadata_func.yaml +0 -127
  101. brkraw-0.5.0rc1/brkraw/default/specs/mrs.yaml +0 -71
  102. brkraw-0.5.0rc1/brkraw/default/specs/mrs_transforms.py +0 -26
  103. brkraw-0.5.0rc1/docs/getting-started/viewer.md +0 -52
  104. brkraw-0.5.0rc1/docs/reference/cli-extensions.md +0 -107
  105. brkraw-0.5.0rc1/docs/reference/hook-packages.md +0 -115
  106. brkraw-0.5.0rc1/tests/test_core/__init__.py +0 -0
  107. {brkraw-0.5.0rc1 → brkraw-0.5.1}/.github/DISCUSSION_TEMPLATE/proposal.yml +0 -0
  108. {brkraw-0.5.0rc1 → brkraw-0.5.1}/.github/DISCUSSION_TEMPLATE/question.yml +0 -0
  109. {brkraw-0.5.0rc1 → brkraw-0.5.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  110. {brkraw-0.5.0rc1 → brkraw-0.5.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  111. {brkraw-0.5.0rc1 → brkraw-0.5.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  112. {brkraw-0.5.0rc1 → brkraw-0.5.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  113. {brkraw-0.5.0rc1 → brkraw-0.5.1}/.github/workflows/ci.yml +0 -0
  114. {brkraw-0.5.0rc1 → brkraw-0.5.1}/.github/workflows/docs.yml +0 -0
  115. {brkraw-0.5.0rc1 → brkraw-0.5.1}/CODE_OF_CONDUCT.md +0 -0
  116. {brkraw-0.5.0rc1 → brkraw-0.5.1}/CONTRIBUTING.md +0 -0
  117. {brkraw-0.5.0rc1 → brkraw-0.5.1}/LICENSE +0 -0
  118. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/apps/__init__.py +0 -0
  119. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/apps/addon/__init__.py +0 -0
  120. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/apps/addon/core.py +0 -0
  121. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/apps/addon/dependencies.py +0 -0
  122. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/apps/addon/installation.py +0 -0
  123. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/apps/addon/io.py +0 -0
  124. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/apps/hook/__init__.py +0 -0
  125. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/apps/loader/__init__.py +0 -0
  126. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/apps/loader/formatter.py +0 -0
  127. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/apps/loader/info/__init__.py +0 -0
  128. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/apps/loader/info/scan.yaml +0 -0
  129. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/apps/loader/info/study.py +0 -0
  130. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/apps/loader/info/study.yaml +0 -0
  131. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/apps/loader/info/transform.py +0 -0
  132. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/cli/__init__.py +0 -0
  133. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/cli/commands/__init__.py +0 -0
  134. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/cli/commands/addon.py +0 -0
  135. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/cli/commands/config.py +0 -0
  136. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/cli/commands/info.py +0 -0
  137. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/cli/commands/init.py +0 -0
  138. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/cli/commands/params.py +0 -0
  139. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/cli/commands/prune.py +0 -0
  140. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/cli/main.py +0 -0
  141. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/cli/utils.py +0 -0
  142. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/core/__init__.py +0 -0
  143. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/core/entrypoints.py +0 -0
  144. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/core/formatter.py +0 -0
  145. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/core/fs.py +0 -0
  146. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/core/jcamp.py +0 -0
  147. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/core/parameters.py +0 -0
  148. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/core/zip.py +0 -0
  149. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/dataclasses/__init__.py +0 -0
  150. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/dataclasses/node.py +0 -0
  151. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/dataclasses/reco.py +0 -0
  152. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/dataclasses/scan.py +0 -0
  153. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/dataclasses/study.py +0 -0
  154. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/default/__init__.py +0 -0
  155. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/default/pruner_specs/deid4share.yaml +0 -0
  156. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/resolver/__init__.py +0 -0
  157. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/resolver/datatype.py +0 -0
  158. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/resolver/fid.py +0 -0
  159. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/resolver/helpers.py +0 -0
  160. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/resolver/image.py +0 -0
  161. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/resolver/nifti.py +0 -0
  162. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/resolver/shape.py +0 -0
  163. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/schema/__init__.py +0 -0
  164. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/schema/meta.yaml +0 -0
  165. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/schema/niftiheader.yaml +0 -0
  166. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/schema/pruner.yaml +0 -0
  167. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/schema/rules.yaml +0 -0
  168. {brkraw-0.5.0rc1/brkraw/specs/converter → brkraw-0.5.1/brkraw/specs/hook}/__init__.py +1 -1
  169. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/specs/meta/__init__.py +0 -0
  170. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/specs/meta/validator.py +0 -0
  171. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/specs/pruner/__init__.py +0 -0
  172. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/specs/pruner/logic.py +0 -0
  173. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/specs/pruner/validator.py +0 -0
  174. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/specs/remapper/__init__.py +0 -0
  175. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/specs/rules/__init__.py +0 -0
  176. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/specs/rules/logic.py +0 -0
  177. {brkraw-0.5.0rc1 → brkraw-0.5.1}/brkraw/specs/rules/validator.py +0 -0
  178. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/api/addon.md +0 -0
  179. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/api/info.md +0 -0
  180. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/api/prune.md +0 -0
  181. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/assets/brkraw-logo-dark.svg +0 -0
  182. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/assets/brkraw-logo-light.svg +0 -0
  183. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/assets/brkraw-logo.svg +0 -0
  184. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/assets/favicon-16.png +0 -0
  185. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/assets/favicon-192.png +0 -0
  186. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/assets/favicon-32.png +0 -0
  187. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/assets/favicon-512.png +0 -0
  188. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/assets/favicon-dark.svg +0 -0
  189. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/assets/favicon-light.svg +0 -0
  190. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/assets/favicon.ico +0 -0
  191. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/assets/favicon.svg +0 -0
  192. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/assets/site.webmanifest +0 -0
  193. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/cli/config.md +0 -0
  194. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/cli/prune.md +0 -0
  195. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/getting-started/configuration.md +0 -0
  196. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/overrides/404.html +0 -0
  197. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/overrides/partials/extrahead.html +0 -0
  198. {brkraw-0.5.0rc1 → brkraw-0.5.1}/docs/stylesheets/extra.css +0 -0
  199. {brkraw-0.5.0rc1 → brkraw-0.5.1}/scripts/tag_and_push.py +0 -0
  200. {brkraw-0.5.0rc1 → brkraw-0.5.1}/tests/helpers.py +0 -0
  201. {brkraw-0.5.0rc1/tests → brkraw-0.5.1/tests/test_01_core}/__init__.py +0 -0
  202. {brkraw-0.5.0rc1/tests/test_core → brkraw-0.5.1/tests/test_01_core}/fixtures/acqp_EPI_pv5_1.jdx +0 -0
  203. {brkraw-0.5.0rc1/tests/test_core → brkraw-0.5.1/tests/test_01_core}/fixtures/method_EPI_pv5_1.jdx +0 -0
  204. {brkraw-0.5.0rc1/tests/test_core → brkraw-0.5.1/tests/test_01_core}/fixtures/method_FLASH_pv360_3_1.jdx +0 -0
  205. {brkraw-0.5.0rc1/tests/test_core → brkraw-0.5.1/tests/test_01_core}/test_formatter.py +0 -0
  206. {brkraw-0.5.0rc1/tests/test_core → brkraw-0.5.1/tests/test_01_core}/test_resources.py +0 -0
@@ -0,0 +1,10 @@
1
+ # AI coding instructions
2
+
3
+ - This repository is a Python package.
4
+ - Use the project-local virtualenv at `.venv` for Python commands.
5
+ - Target Python version: >= 3.8 (flag compatibility issues with versions supported by `pyproject.toml`).
6
+ - Prefer pure functions and type hints.
7
+ - Do not introduce new dependencies unless explicitly asked.
8
+ - Follow existing style and naming conventions.
9
+ - Avoid large refactors unless requested.
10
+ - Add/update tests for behavior changes when practical.
@@ -40,42 +40,13 @@ jobs:
40
40
  - name: Install build tooling
41
41
  run: |
42
42
  python -m pip install --upgrade pip
43
- python -m pip install build twine
43
+ python -m pip install build twine packaging
44
44
  - name: Verify version matches tag
45
45
  if: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && inputs.tag != '') }}
46
46
  env:
47
47
  TAG: ${{ steps.tag.outputs.value }}
48
48
  run: |
49
- python -c 'code = """import os
50
- import sys
51
- import re
52
- import tomllib
53
- from pathlib import Path
54
- from packaging.version import parse
55
-
56
- tag = os.environ["TAG"]
57
- print(f"Target Tag: {tag}")
58
-
59
- pyproject = tomllib.loads(Path("pyproject.toml").read_text(encoding="utf-8"))
60
- version = pyproject.get("project", {}).get("version")
61
- if not version:
62
- version_path = pyproject.get("tool", {}).get("hatch", {}).get("version", {}).get("path")
63
- if not version_path:
64
- raise SystemExit("No version in pyproject.toml and no hatch version path found.")
65
- text = Path(version_path).read_text(encoding="utf-8")
66
- match = re.search(r"__version__\\s*=\\s*[\"\x27]([^\"]+)[\"\x27]", text)
67
- if not match:
68
- raise SystemExit(f"No __version__ found in {version_path}")
69
- version = match.group(1)
70
-
71
- print(f"Detected Package Version: {version}")
72
-
73
- # Normalize versions and compare (handles v-prefix and alpha/beta notations)
74
- if parse(tag) != parse(version):
75
- raise SystemExit(f"Tag {tag} does not match package version {version}.")
76
-
77
- print("Version check passed!")
78
- \"\"\"; exec(code)'
49
+ python scripts/verify_release_version.py
79
50
  - name: Build dist
80
51
  run: python -m build
81
52
  - name: Check dist metadata
@@ -68,7 +68,7 @@ jobs:
68
68
 
69
69
  notes = Path("RELEASE_NOTES.md").read_text(encoding="utf-8").strip()
70
70
  title = f"Release {tag}"
71
- body = f"[Release {tag}]({release_url})\\n\\n{notes}"
71
+ body = f"[Release {tag}]({release_url})\n\n{notes}"
72
72
 
73
73
  query = {
74
74
  "query": """
@@ -0,0 +1,54 @@
1
+ name: Release On Merge
2
+
3
+ on:
4
+ pull_request:
5
+ types: [closed]
6
+ branches: [main]
7
+
8
+ permissions:
9
+ contents: write
10
+
11
+ jobs:
12
+ tag_release:
13
+ if: ${{ github.repository == 'BrkRaw/brkraw' && github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'release') }}
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ with:
18
+ fetch-depth: 0
19
+ - name: Detect version change
20
+ id: version
21
+ run: |
22
+ base_sha="${{ github.event.pull_request.base.sha }}"
23
+ merge_sha="${{ github.event.pull_request.merge_commit_sha }}"
24
+ if ! git diff --name-only "$base_sha" "$merge_sha" | grep -q '^src/brkraw/__init__.py$'; then
25
+ echo "changed=false" >> "$GITHUB_OUTPUT"
26
+ exit 0
27
+ fi
28
+ version=$(python3 - <<'PY'
29
+ import re
30
+ from pathlib import Path
31
+
32
+ text = Path("src/brkraw/__init__.py").read_text(encoding="utf-8")
33
+ match = re.search(
34
+ r"^\\s*__version__(?:\\s*:\\s*[^=]+)?\\s*=\\s*['\\\"]([^'\\\"]+)['\\\"]",
35
+ text,
36
+ re.M,
37
+ )
38
+ if not match:
39
+ raise SystemExit("No __version__ found in src/brkraw/__init__.py")
40
+ print(match.group(1))
41
+ PY
42
+ )
43
+ echo "changed=true" >> "$GITHUB_OUTPUT"
44
+ echo "value=$version" >> "$GITHUB_OUTPUT"
45
+ - name: Create and push tag
46
+ if: ${{ steps.version.outputs.changed == 'true' }}
47
+ run: |
48
+ tag="${{ steps.version.outputs.value }}"
49
+ if git rev-parse "$tag" >/dev/null 2>&1; then
50
+ echo "Tag $tag already exists. Skipping."
51
+ exit 0
52
+ fi
53
+ git tag "$tag" "${{ github.event.pull_request.merge_commit_sha }}"
54
+ git push origin "$tag"
@@ -23,3 +23,4 @@ site/
23
23
  .idea/
24
24
  .vscode/
25
25
  *.lock
26
+ .tmp
@@ -0,0 +1,6 @@
1
+ MD007: false
2
+ MD013:
3
+ line_length: 120
4
+ tables: false
5
+ MD022: false
6
+ MD032: false
brkraw-0.5.1/AGENTS.md ADDED
@@ -0,0 +1,22 @@
1
+ # Codex instructions (repo-wide)
2
+
3
+ ## Environment
4
+ - Use the project-local virtualenv at `.venv` (interpreter: `.venv/bin/python`) when running Python commands.
5
+ - Target Python version for development: >= 3.8. If a change would break
6
+ versions supported by `pyproject.toml`, call it out before proceeding.
7
+
8
+ ## Project constraints
9
+ - This repository is a Python package.
10
+ - Prefer pure functions and type hints.
11
+ - Do not introduce new dependencies unless explicitly requested.
12
+ - Follow existing style and naming conventions.
13
+ - Avoid large refactors unless requested.
14
+
15
+ ## Quality bar
16
+ - Add or update tests for behavior changes when practical.
17
+ - Keep user-facing CLI output stable unless explicitly requested.
18
+ - Prefer clear errors over silent failures; avoid broad `except Exception` unless there is a strong reason.
19
+
20
+ ## Handy commands
21
+ - Run tests: `.venv/bin/python -m pytest`
22
+ - Lint/type check: only run tools already configured in the repo (do not add new tooling unless asked).
@@ -0,0 +1,49 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use this software, please cite it as below."
3
+ title: "BrkRaw: A modular toolkit for Bruker MRI raw-data handling"
4
+ type: software
5
+
6
+ authors:
7
+ - family-names: Lee
8
+ given-names: Sung-Ho
9
+ orcid: "https://orcid.org/0000-0001-5292-0747"
10
+ affiliation:
11
+ - "Center for Animal MRI (CAMRI), University of North Carolina at Chapel Hill, Chapel Hill, NC, United States"
12
+ - "Biomedical Research Imaging Center (BRIC), University of North Carolina at Chapel Hill, Chapel Hill, NC, United States"
13
+ - "Department of Neurology, UNC School of Medicine, Chapel Hill, NC, United States"
14
+ - family-names: Devenyi
15
+ given-names: Gabriel A.
16
+ orcid: "https://orcid.org/0000-0002-7766-1187"
17
+ affiliation:
18
+ - "Cerebral Imaging Centre, Douglas Mental Health University Institute, Montreal, QC, Canada"
19
+ - "Department of Psychiatry, McGill University, Montreal, QC, Canada"
20
+ - family-names: Ban
21
+ given-names: Woomi
22
+ orcid: "https://orcid.org/0000-0003-2003-717X"
23
+ affiliation:
24
+ - "Center for Animal MRI (CAMRI), University of North Carolina at Chapel Hill, Chapel Hill, NC, United States"
25
+ - "Biomedical Research Imaging Center (BRIC), University of North Carolina at Chapel Hill, Chapel Hill, NC, United States"
26
+ - "Department of Neurology, UNC School of Medicine, Chapel Hill, NC, United States"
27
+ - family-names: Shih
28
+ given-names: Yen-Yu Ian
29
+ orcid: "https://orcid.org/0000-0001-6529-911X"
30
+ affiliation:
31
+ - "Center for Animal MRI (CAMRI), University of North Carolina at Chapel Hill, Chapel Hill, NC, United States"
32
+ - "Biomedical Research Imaging Center (BRIC), University of North Carolina at Chapel Hill, Chapel Hill, NC, United States"
33
+ - "Department of Neurology, UNC School of Medicine, Chapel Hill, NC, United States"
34
+
35
+ doi: "10.5281/zenodo.3818614"
36
+ repository-code: "https://github.com/BrkRaw/brkraw"
37
+ url: "https://brkraw.github.io"
38
+
39
+ license: "GPL-3.0-only"
40
+
41
+ keywords:
42
+ - Bruker
43
+ - MRI
44
+ - preclinical MRI
45
+ - BIDS
46
+ - neuroimaging
47
+
48
+ version: "0.5.1"
49
+ date-released: "2026-01-19"
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: brkraw
3
- Version: 0.5.0rc1
3
+ Version: 0.5.1
4
4
  Summary: Toolkit for loading Bruker Paravision datasets, mapping metadata, and exporting NIfTI
5
5
  Project-URL: Homepage, https://brkraw.github.io
6
6
  Maintainer-email: SungHo Lee <shlee@unc.edu>
7
7
  License: GNLv3
8
8
  License-File: LICENSE
9
9
  Keywords: bruker,cli,conversion,dataset,mri,neuroimaging,nifti,paravision,preclinical
10
- Classifier: Development Status :: 4 - Beta
10
+ Classifier: Development Status :: 5 - Production/Stable
11
11
  Classifier: Intended Audience :: Science/Research
12
12
  Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
13
13
  Classifier: Natural Language :: English
@@ -44,11 +44,38 @@ Description-Content-Type: text/markdown
44
44
  </picture>
45
45
  <!-- markdownlint-enable MD041 MD033 MD013 -->
46
46
 
47
- A modular toolkit for preclinical MRI: from raw studies to reproducible outputs.
47
+ [![DOI](https://zenodo.org/badge/245546149.svg)](https://doi.org/10.5281/zenodo.3818614)
48
48
 
49
- BrkRaw (v0.5.0rc1) converts raw data into standardized, neuroimaging-ready
49
+ A modular toolkit for Bruker MRI raw-data handling.
50
+
51
+ BrkRaw (v0.5.1) converts raw data into standardized, neuroimaging-ready
50
52
  datasets, with extensible rules/specs and plugin hooks.
51
53
 
52
54
  - Documentation: [brkraw.github.io](https://brkraw.github.io/)
53
55
  - Releases: [BrkRaw/brkraw releases](https://github.com/BrkRaw/brkraw/releases)
54
56
  - PyPI: [brkraw on PyPI](https://pypi.org/project/brkraw/)
57
+
58
+ ## Citation
59
+
60
+ If you use BrkRaw in your research, please cite it.
61
+
62
+ - Citation metadata: [CITATION.cff](./CITATION.cff)
63
+ - DOI (Zenodo): [10.5281/zenodo.3818614](https://doi.org/10.5281/zenodo.3818614)
64
+
65
+ ### Cite as (BibTeX)
66
+
67
+ <!-- BEGIN: brkraw-bibtex -->
68
+ ```biblatex
69
+ @software{brkraw_2026,
70
+ author = {Lee, Sung-Ho and Devenyi, Gabriel A and Ban, Woomi and Shih, Yen-Yu Ian},
71
+ title = {BrkRaw: A modular toolkit for Bruker MRI raw-data handling},
72
+ year = {2026},
73
+ version = {0.5.0},
74
+ doi = {10.5281/zenodo.3818614},
75
+ url = {https://github.com/BrkRaw/brkraw},
76
+ note = {Documentation: https://brkraw.github.io},
77
+ license = {GPL-3.0-only},
78
+ date = {2026-01-13}
79
+ }
80
+ ```
81
+ <!-- END: brkraw-bibtex -->
brkraw-0.5.1/README.md ADDED
@@ -0,0 +1,43 @@
1
+ <!-- markdownlint-disable MD041 MD033 MD013 -->
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="docs/assets/brkraw-logo-dark.svg">
4
+ <source media="(prefers-color-scheme: light)" srcset="docs/assets/brkraw-logo-light.svg">
5
+ <img src="docs/assets/brkraw-logo-light.svg" width="220" alt="BrkRaw logo">
6
+ </picture>
7
+ <!-- markdownlint-enable MD041 MD033 MD013 -->
8
+
9
+ [![DOI](https://zenodo.org/badge/245546149.svg)](https://doi.org/10.5281/zenodo.3818614)
10
+
11
+ A modular toolkit for Bruker MRI raw-data handling.
12
+
13
+ BrkRaw (v0.5.1) converts raw data into standardized, neuroimaging-ready
14
+ datasets, with extensible rules/specs and plugin hooks.
15
+
16
+ - Documentation: [brkraw.github.io](https://brkraw.github.io/)
17
+ - Releases: [BrkRaw/brkraw releases](https://github.com/BrkRaw/brkraw/releases)
18
+ - PyPI: [brkraw on PyPI](https://pypi.org/project/brkraw/)
19
+
20
+ ## Citation
21
+
22
+ If you use BrkRaw in your research, please cite it.
23
+
24
+ - Citation metadata: [CITATION.cff](./CITATION.cff)
25
+ - DOI (Zenodo): [10.5281/zenodo.3818614](https://doi.org/10.5281/zenodo.3818614)
26
+
27
+ ### Cite as (BibTeX)
28
+
29
+ <!-- BEGIN: brkraw-bibtex -->
30
+ ```biblatex
31
+ @software{brkraw_2026,
32
+ author = {Lee, Sung-Ho and Devenyi, Gabriel A and Ban, Woomi and Shih, Yen-Yu Ian},
33
+ title = {BrkRaw: A modular toolkit for Bruker MRI raw-data handling},
34
+ year = {2026},
35
+ version = {0.5.0},
36
+ doi = {10.5281/zenodo.3818614},
37
+ url = {https://github.com/BrkRaw/brkraw},
38
+ note = {Documentation: https://brkraw.github.io},
39
+ license = {GPL-3.0-only},
40
+ date = {2026-01-13}
41
+ }
42
+ ```
43
+ <!-- END: brkraw-bibtex -->
@@ -0,0 +1,13 @@
1
+ # Release v0.5.1
2
+
3
+ Date: 2026-01-19
4
+ Changes since 0.5.0
5
+
6
+ - chore: prepare release v0.5.1 (5902a9d)
7
+ - Handle quoted CITATION fields in release prep (bc0bbc8)
8
+ - docs: update contributors (78d6da5)
9
+ - Use gh pr view for release PR lookup (af9fdf1)
10
+ - Make release PR creation compatible with gh (4a939a0)
11
+ - Fix release PR lookup (17cf410)
12
+ - Preserve study fields in override layout (edc67ba)
13
+ - Fix publish version check script (719ae4c)
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = '0.5.0rc1'
3
+ __version__ = '0.5.1'
4
4
  from .apps.loader import BrukerLoader
5
5
 
6
6
 
@@ -7,7 +7,7 @@ import importlib.metadata
7
7
  import logging
8
8
  import re
9
9
  from pathlib import Path
10
- from typing import Any, Dict, List, Mapping, Optional, Sequence, Tuple, Union
10
+ from typing import Any, Callable, Dict, List, Mapping, Optional, Sequence, Tuple, Union, cast
11
11
 
12
12
  try:
13
13
  from importlib import resources
@@ -17,7 +17,7 @@ import yaml
17
17
 
18
18
  from ...core import config as config_core
19
19
  from ...core.entrypoints import list_entry_points
20
- from ...specs.converter.logic import DEFAULT_GROUP
20
+ from ...specs.hook.logic import DEFAULT_GROUP
21
21
  from ..addon import installation as addon_install
22
22
  from ..addon import dependencies as addon_deps
23
23
  from ..addon.io import write_file as _write_file
@@ -28,6 +28,41 @@ REGISTRY_FILENAME = "hooks.yaml"
28
28
  MANIFEST_NAMES = ("brkraw_hook.yaml", "brkraw_hook.yml")
29
29
 
30
30
 
31
+ def _metadata_get(
32
+ dist: Optional[importlib.metadata.Distribution],
33
+ key: str,
34
+ default: Optional[str] = None,
35
+ ) -> Optional[str]:
36
+ """Typed helper to read distribution metadata."""
37
+ if dist is None:
38
+ return default
39
+ meta = cast(Mapping[str, str], dist.metadata)
40
+ return meta.get(key, default)
41
+
42
+
43
+ def _packages_distributions() -> Mapping[str, List[str]]:
44
+ packages_distributions = getattr(importlib.metadata, "packages_distributions", None)
45
+ if packages_distributions is not None:
46
+ return cast(Callable[[], Mapping[str, List[str]]], packages_distributions)()
47
+
48
+ mapping: Dict[str, List[str]] = {}
49
+ for dist in importlib.metadata.distributions():
50
+ read_text = getattr(dist, "read_text", None)
51
+ top_level_text = ""
52
+ if callable(read_text):
53
+ top_level = read_text("top_level.txt")
54
+ if isinstance(top_level, str):
55
+ top_level_text = top_level
56
+ dist_name = _metadata_get(dist, "Name")
57
+ if not dist_name:
58
+ continue
59
+ for package in top_level_text.splitlines():
60
+ package = package.strip()
61
+ if package:
62
+ mapping.setdefault(package, []).append(dist_name)
63
+ return mapping
64
+
65
+
31
66
  def list_hooks(*, root: Optional[Union[str, Path]] = None) -> List[Dict[str, Any]]:
32
67
  hooks = _collect_hooks()
33
68
  registry = _load_registry(root=root)
@@ -88,13 +123,26 @@ def uninstall_hook(
88
123
  *,
89
124
  root: Optional[Union[str, Path]] = None,
90
125
  force: bool = False,
91
- ) -> Tuple[str, Dict[str, List[str]]]:
126
+ ) -> Tuple[str, Dict[str, List[str]], bool]:
92
127
  registry = _load_registry(root=root)
93
128
  hooks = registry.get("hooks", {})
94
129
  hook_name = _resolve_hook_name(target)
95
130
  entry = hooks.get(hook_name)
131
+ if entry is None:
132
+ entry_matches = [
133
+ name
134
+ for name, data in hooks.items()
135
+ if target in (data.get("entrypoints") or [])
136
+ ]
137
+ if len(entry_matches) == 1:
138
+ hook_name = entry_matches[0]
139
+ entry = hooks.get(hook_name)
140
+ elif entry_matches:
141
+ names = ", ".join(sorted(entry_matches))
142
+ raise ValueError(f"Multiple hooks match {target}: {names}")
96
143
  if entry is None:
97
144
  raise LookupError(f"Hook not installed: {hook_name}")
145
+ module_missing = not list_entry_points(DEFAULT_GROUP, name=hook_name)
98
146
  removed: Dict[str, List[str]] = {
99
147
  "specs": [],
100
148
  "pruner_specs": [],
@@ -113,7 +161,7 @@ def uninstall_hook(
113
161
  removed[kind].append(relpath)
114
162
  hooks.pop(hook_name, None)
115
163
  _save_registry(registry, root=root)
116
- return hook_name, removed
164
+ return hook_name, removed, module_missing
117
165
 
118
166
 
119
167
  def _install_hook(
@@ -347,7 +395,7 @@ def _resolve_distribution(ep: importlib.metadata.EntryPoint) -> Optional[importl
347
395
  pkg = getattr(ep, "module", "").split(".")[0]
348
396
  if not pkg:
349
397
  return None
350
- mapping = importlib.metadata.packages_distributions()
398
+ mapping = _packages_distributions()
351
399
  dist_names = mapping.get(pkg, [])
352
400
  if not dist_names:
353
401
  return None
@@ -360,26 +408,26 @@ def _resolve_distribution(ep: importlib.metadata.EntryPoint) -> Optional[importl
360
408
  def _dist_name(dist: Optional[importlib.metadata.Distribution]) -> Optional[str]:
361
409
  if dist is None:
362
410
  return None
363
- return dist.metadata.get("Name")
411
+ return _metadata_get(dist, "Name")
364
412
 
365
413
 
366
414
  def _dist_version(dist: Optional[importlib.metadata.Distribution]) -> str:
367
415
  if dist is None:
368
416
  return "<Unknown>"
369
- return dist.metadata.get("Version", "<Unknown>")
417
+ return _metadata_get(dist, "Version", "<Unknown>") or "<Unknown>"
370
418
 
371
419
 
372
420
  def _dist_description(dist: Optional[importlib.metadata.Distribution]) -> str:
373
421
  if dist is None:
374
422
  return "<Unknown>"
375
- return dist.metadata.get("Summary", "<Unknown>")
423
+ return _metadata_get(dist, "Summary", "<Unknown>") or "<Unknown>"
376
424
 
377
425
 
378
426
  def _dist_author(dist: Optional[importlib.metadata.Distribution]) -> str:
379
427
  if dist is None:
380
428
  return "<Unknown>"
381
429
  for key in ("Author", "Author-email", "Maintainer", "Maintainer-email"):
382
- value = dist.metadata.get(key)
430
+ value = _metadata_get(dist, key)
383
431
  if value:
384
432
  return value
385
433
  return "<Unknown>"
@@ -394,7 +442,7 @@ def _load_manifest(
394
442
  manifest = _find_manifest(dist, packages=packages)
395
443
  if manifest is None:
396
444
  raise FileNotFoundError(
397
- f"No hook manifest found in {dist.metadata.get('Name', '<Unknown>')}"
445
+ f"No hook manifest found in {_metadata_get(dist, 'Name', '<Unknown>')}"
398
446
  )
399
447
  data = _read_yaml(manifest)
400
448
  return manifest, data
@@ -19,7 +19,7 @@ from pathlib import Path
19
19
 
20
20
  from ...core import config as config_core
21
21
  from ...core.config import resolve_root
22
- from ...specs import converter as converter_core
22
+ from ...specs import hook as converter_core
23
23
  from ...specs.pruner import prune_dataset_to_zip
24
24
  from ...specs.rules import load_rules, select_rule_use
25
25
  from ...dataclasses import Scan, Study
@@ -350,6 +350,7 @@ class BrukerLoader:
350
350
  override_subject_type: Optional[SubjectType] = None,
351
351
  override_subject_pose: Optional[SubjectPose] = None,
352
352
  flip_x: bool = False,
353
+ flatten_fg: bool = False,
353
354
  xyz_units: XYZUNIT = 'mm',
354
355
  t_units: TUNIT = 'sec'):
355
356
  """Return NIfTI image(s) for a scan/reco via attached helper.
@@ -377,6 +378,7 @@ class BrukerLoader:
377
378
  override_subject_type=override_subject_type,
378
379
  override_subject_pose=override_subject_pose,
379
380
  flip_x=flip_x,
381
+ flatten_fg=flatten_fg,
380
382
  xyz_units=xyz_units,
381
383
  t_units=t_units,
382
384
  )
@@ -392,6 +394,7 @@ class BrukerLoader:
392
394
  override_subject_type: Optional[SubjectType] = None,
393
395
  override_subject_pose: Optional[SubjectPose] = None,
394
396
  flip_x: bool = False,
397
+ flatten_fg: bool = False,
395
398
  xyz_units: XYZUNIT = "mm",
396
399
  t_units: TUNIT = "sec",
397
400
  hook_args_by_name: Optional[Mapping[str, Mapping[str, Any]]] = None,
@@ -406,6 +409,7 @@ class BrukerLoader:
406
409
  override_subject_type=override_subject_type,
407
410
  override_subject_pose=override_subject_pose,
408
411
  flip_x=flip_x,
412
+ flatten_fg=flatten_fg,
409
413
  xyz_units=xyz_units,
410
414
  t_units=t_units,
411
415
  hook_args_by_name=hook_args_by_name,