xnatbidscli 2.0.0__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.
- xnatbidscli-2.0.0/.claude/CLAUDE.md +1 -0
- xnatbidscli-2.0.0/.github/workflows/publish.yml +25 -0
- xnatbidscli-2.0.0/.gitignore +212 -0
- xnatbidscli-2.0.0/.python-version +1 -0
- xnatbidscli-2.0.0/.readthedocs.yaml +15 -0
- xnatbidscli-2.0.0/AGENTS.md +21 -0
- xnatbidscli-2.0.0/CHANGELOG.md +3 -0
- xnatbidscli-2.0.0/LICENSE +21 -0
- xnatbidscli-2.0.0/PKG-INFO +65 -0
- xnatbidscli-2.0.0/README.md +29 -0
- xnatbidscli-2.0.0/docs/assets/images/favicon.png +0 -0
- xnatbidscli-2.0.0/docs/assets/images/logo.png +0 -0
- xnatbidscli-2.0.0/docs/assets/js/faq.js +12 -0
- xnatbidscli-2.0.0/docs/changelog.md +63 -0
- xnatbidscli-2.0.0/docs/cli/bidsmap.md +51 -0
- xnatbidscli-2.0.0/docs/cli/cubids.md +24 -0
- xnatbidscli-2.0.0/docs/cli/download.md +97 -0
- xnatbidscli-2.0.0/docs/cli/login.md +19 -0
- xnatbidscli-2.0.0/docs/cli/mriconfig.md +58 -0
- xnatbidscli-2.0.0/docs/cli/mriconvert.md +101 -0
- xnatbidscli-2.0.0/docs/cli/physioconvert.md +50 -0
- xnatbidscli-2.0.0/docs/cli/query.md +85 -0
- xnatbidscli-2.0.0/docs/design.md +15 -0
- xnatbidscli-2.0.0/docs/excel.md +39 -0
- xnatbidscli-2.0.0/docs/faq.md +135 -0
- xnatbidscli-2.0.0/docs/index.md +13 -0
- xnatbidscli-2.0.0/docs/installation.md +29 -0
- xnatbidscli-2.0.0/docs/manual.md +60 -0
- xnatbidscli-2.0.0/docs/quickstart.md +112 -0
- xnatbidscli-2.0.0/docs/requirements.txt +1 -0
- xnatbidscli-2.0.0/pyproject.toml +79 -0
- xnatbidscli-2.0.0/src/assets/mriconvert_qc.json +82 -0
- xnatbidscli-2.0.0/src/assets/physioconvert_qc.json +33 -0
- xnatbidscli-2.0.0/src/xnatbidscli/__init__.py +6 -0
- xnatbidscli-2.0.0/src/xnatbidscli/archive.py +67 -0
- xnatbidscli-2.0.0/src/xnatbidscli/bidsmap.py +820 -0
- xnatbidscli-2.0.0/src/xnatbidscli/cli.py +525 -0
- xnatbidscli-2.0.0/src/xnatbidscli/cubids.py +149 -0
- xnatbidscli-2.0.0/src/xnatbidscli/download.py +1009 -0
- xnatbidscli-2.0.0/src/xnatbidscli/login.py +142 -0
- xnatbidscli-2.0.0/src/xnatbidscli/mriconfig.py +560 -0
- xnatbidscli-2.0.0/src/xnatbidscli/mriconvert.py +890 -0
- xnatbidscli-2.0.0/src/xnatbidscli/physioconvert.py +845 -0
- xnatbidscli-2.0.0/src/xnatbidscli/query.py +684 -0
- xnatbidscli-2.0.0/src/xnatbidscli/sysinfo.py +12 -0
- xnatbidscli-2.0.0/test_plan.md +208 -0
- xnatbidscli-2.0.0/zensical.toml +70 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@../AGENTS.md
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
publish:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
permissions:
|
|
11
|
+
# Required for PyPI trusted publishing (OIDC) — no API token needed.
|
|
12
|
+
id-token: write
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
with:
|
|
16
|
+
# hatch-vcs needs full history/tags to compute the version.
|
|
17
|
+
fetch-depth: 0
|
|
18
|
+
|
|
19
|
+
- uses: astral-sh/setup-uv@v5
|
|
20
|
+
|
|
21
|
+
- name: Build sdist and wheel
|
|
22
|
+
run: uv build
|
|
23
|
+
|
|
24
|
+
- name: Publish to PyPI
|
|
25
|
+
run: uv publish
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# specifics
|
|
2
|
+
data/
|
|
3
|
+
uv.lock
|
|
4
|
+
biopac*
|
|
5
|
+
|
|
6
|
+
# Byte-compiled / optimized / DLL files
|
|
7
|
+
__pycache__/
|
|
8
|
+
*.py[codz]
|
|
9
|
+
*$py.class
|
|
10
|
+
|
|
11
|
+
# C extensions
|
|
12
|
+
*.so
|
|
13
|
+
|
|
14
|
+
# Distribution / packaging
|
|
15
|
+
.Python
|
|
16
|
+
build/
|
|
17
|
+
develop-eggs/
|
|
18
|
+
dist/
|
|
19
|
+
downloads/
|
|
20
|
+
eggs/
|
|
21
|
+
.eggs/
|
|
22
|
+
lib/
|
|
23
|
+
lib64/
|
|
24
|
+
parts/
|
|
25
|
+
sdist/
|
|
26
|
+
var/
|
|
27
|
+
wheels/
|
|
28
|
+
share/python-wheels/
|
|
29
|
+
*.egg-info/
|
|
30
|
+
.installed.cfg
|
|
31
|
+
*.egg
|
|
32
|
+
MANIFEST
|
|
33
|
+
|
|
34
|
+
# PyInstaller
|
|
35
|
+
# Usually these files are written by a python script from a template
|
|
36
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
37
|
+
*.manifest
|
|
38
|
+
*.spec
|
|
39
|
+
|
|
40
|
+
# Installer logs
|
|
41
|
+
pip-log.txt
|
|
42
|
+
pip-delete-this-directory.txt
|
|
43
|
+
|
|
44
|
+
# Unit test / coverage reports
|
|
45
|
+
htmlcov/
|
|
46
|
+
.tox/
|
|
47
|
+
.nox/
|
|
48
|
+
.coverage
|
|
49
|
+
.coverage.*
|
|
50
|
+
.cache
|
|
51
|
+
nosetests.xml
|
|
52
|
+
coverage.xml
|
|
53
|
+
*.cover
|
|
54
|
+
*.py.cover
|
|
55
|
+
.hypothesis/
|
|
56
|
+
.pytest_cache/
|
|
57
|
+
cover/
|
|
58
|
+
|
|
59
|
+
# Translations
|
|
60
|
+
*.mo
|
|
61
|
+
*.pot
|
|
62
|
+
|
|
63
|
+
# Django stuff:
|
|
64
|
+
*.log
|
|
65
|
+
local_settings.py
|
|
66
|
+
db.sqlite3
|
|
67
|
+
db.sqlite3-journal
|
|
68
|
+
|
|
69
|
+
# Flask stuff:
|
|
70
|
+
instance/
|
|
71
|
+
.webassets-cache
|
|
72
|
+
|
|
73
|
+
# Scrapy stuff:
|
|
74
|
+
.scrapy
|
|
75
|
+
|
|
76
|
+
# Sphinx documentation
|
|
77
|
+
docs/_build/
|
|
78
|
+
|
|
79
|
+
# PyBuilder
|
|
80
|
+
.pybuilder/
|
|
81
|
+
target/
|
|
82
|
+
|
|
83
|
+
# Jupyter Notebook
|
|
84
|
+
.ipynb_checkpoints
|
|
85
|
+
|
|
86
|
+
# IPython
|
|
87
|
+
profile_default/
|
|
88
|
+
ipython_config.py
|
|
89
|
+
|
|
90
|
+
# pyenv
|
|
91
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
92
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
93
|
+
# .python-version
|
|
94
|
+
|
|
95
|
+
# pipenv
|
|
96
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
97
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
98
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
99
|
+
# install all needed dependencies.
|
|
100
|
+
#Pipfile.lock
|
|
101
|
+
|
|
102
|
+
# UV
|
|
103
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
104
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
105
|
+
# commonly ignored for libraries.
|
|
106
|
+
#uv.lock
|
|
107
|
+
|
|
108
|
+
# poetry
|
|
109
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
110
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
111
|
+
# commonly ignored for libraries.
|
|
112
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
113
|
+
#poetry.lock
|
|
114
|
+
#poetry.toml
|
|
115
|
+
|
|
116
|
+
# pdm
|
|
117
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
118
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
119
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
120
|
+
#pdm.lock
|
|
121
|
+
#pdm.toml
|
|
122
|
+
.pdm-python
|
|
123
|
+
.pdm-build/
|
|
124
|
+
|
|
125
|
+
# pixi
|
|
126
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
127
|
+
#pixi.lock
|
|
128
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
129
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
130
|
+
.pixi
|
|
131
|
+
|
|
132
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
133
|
+
__pypackages__/
|
|
134
|
+
|
|
135
|
+
# Celery stuff
|
|
136
|
+
celerybeat-schedule
|
|
137
|
+
celerybeat.pid
|
|
138
|
+
|
|
139
|
+
# SageMath parsed files
|
|
140
|
+
*.sage.py
|
|
141
|
+
|
|
142
|
+
# Environments
|
|
143
|
+
.env
|
|
144
|
+
.envrc
|
|
145
|
+
.venv
|
|
146
|
+
env/
|
|
147
|
+
venv/
|
|
148
|
+
ENV/
|
|
149
|
+
env.bak/
|
|
150
|
+
venv.bak/
|
|
151
|
+
|
|
152
|
+
# Spyder project settings
|
|
153
|
+
.spyderproject
|
|
154
|
+
.spyproject
|
|
155
|
+
|
|
156
|
+
# Rope project settings
|
|
157
|
+
.ropeproject
|
|
158
|
+
|
|
159
|
+
# mkdocs documentation
|
|
160
|
+
/site
|
|
161
|
+
|
|
162
|
+
# mypy
|
|
163
|
+
.mypy_cache/
|
|
164
|
+
.dmypy.json
|
|
165
|
+
dmypy.json
|
|
166
|
+
|
|
167
|
+
# Pyre type checker
|
|
168
|
+
.pyre/
|
|
169
|
+
|
|
170
|
+
# pytype static type analyzer
|
|
171
|
+
.pytype/
|
|
172
|
+
|
|
173
|
+
# Cython debug symbols
|
|
174
|
+
cython_debug/
|
|
175
|
+
|
|
176
|
+
# PyCharm
|
|
177
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
178
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
179
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
180
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
181
|
+
#.idea/
|
|
182
|
+
|
|
183
|
+
# Abstra
|
|
184
|
+
# Abstra is an AI-powered process automation framework.
|
|
185
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
186
|
+
# Learn more at https://abstra.io/docs
|
|
187
|
+
.abstra/
|
|
188
|
+
|
|
189
|
+
# Visual Studio Code
|
|
190
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
191
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
192
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
193
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
194
|
+
# .vscode/
|
|
195
|
+
|
|
196
|
+
# Ruff stuff:
|
|
197
|
+
.ruff_cache/
|
|
198
|
+
|
|
199
|
+
# PyPI configuration file
|
|
200
|
+
.pypirc
|
|
201
|
+
|
|
202
|
+
# Cursor
|
|
203
|
+
# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
|
|
204
|
+
# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
|
|
205
|
+
# refer to https://docs.cursor.com/context/ignore-files
|
|
206
|
+
.cursorignore
|
|
207
|
+
.cursorindexingignore
|
|
208
|
+
|
|
209
|
+
# Marimo
|
|
210
|
+
marimo/_static/
|
|
211
|
+
marimo/_lsp/
|
|
212
|
+
__marimo__/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.11
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
|
|
3
|
+
build:
|
|
4
|
+
os: ubuntu-24.04
|
|
5
|
+
tools:
|
|
6
|
+
python: latest
|
|
7
|
+
jobs:
|
|
8
|
+
install:
|
|
9
|
+
- pip install -r docs/requirements.txt
|
|
10
|
+
build:
|
|
11
|
+
html:
|
|
12
|
+
- zensical build
|
|
13
|
+
post_build:
|
|
14
|
+
- mkdir -p $READTHEDOCS_OUTPUT/html/
|
|
15
|
+
- cp --recursive site/* $READTHEDOCS_OUTPUT/html/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# AGENTS
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This project is a command-line interface for logging into an Extensible Neuroimaging Archive Toolkit (XNAT) server, querying experiments and downloading files, then converting to the Brain Imaging Data Structure (BIDS) standard format.
|
|
6
|
+
|
|
7
|
+
## Always (for every prompt and follow-up)
|
|
8
|
+
|
|
9
|
+
- Always ask clarifying questions if a request is unclear or if there are distinctly different performance or behavior expectations among possible solutions.
|
|
10
|
+
- Always update the README.md and docs when something changes in the code that affects the behaviors described in the README.md or docs. But keep document changes concise so any given page does not end up too long.
|
|
11
|
+
- Always make clear and concise comments and numpy docstrings inside the code. The code should be mostly self-explanatory, and comments should be used to clarify complex logic or design decisions.
|
|
12
|
+
- Always use "uv run" to run anything requiring the environment in this repository.
|
|
13
|
+
- Update the docs/faq.md if any functionality behaviors change.
|
|
14
|
+
- Add every user-facing change under `[Unreleased]` in docs/changelog.md, following [Keep a Changelog](https://keepachangelog.com/en/2.0.0/).
|
|
15
|
+
|
|
16
|
+
## Don't
|
|
17
|
+
|
|
18
|
+
- Don't assume the user wants one option over another without explicitly asking a clarifying question.
|
|
19
|
+
- Don't write code comments that are very verbose or redundant.
|
|
20
|
+
- Don't ever enter, read, or touch a data/ directory. A data/ directory is for user data only and should never be read or modified by the agent.
|
|
21
|
+
- Don't ever query, read, or touch the user's XNAT server. The user's XNAT server is for users only and should never be queried or used by the agent.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 NIMH Data Science and Sharing Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: xnatbidscli
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: CLI for logging into XNAT, downloading neuroimaging experiments, and converting them to BIDS.
|
|
5
|
+
Project-URL: Homepage, https://github.com/nimh-dsst/xnat-bids-cli
|
|
6
|
+
Project-URL: Documentation, https://xnatbidscli.readthedocs.io/
|
|
7
|
+
Project-URL: Repository, https://github.com/nimh-dsst/xnat-bids-cli
|
|
8
|
+
Project-URL: Issues, https://github.com/nimh-dsst/xnat-bids-cli/issues
|
|
9
|
+
Author-email: Eric Earl <eric.earl@nih.gov>
|
|
10
|
+
Maintainer-email: NIMH Data Science and Sharing Team <nimhdsst@mail.nih.gov>
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: Science/Research
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
|
|
22
|
+
Requires-Python: >=3.11
|
|
23
|
+
Requires-Dist: bioread>=3; python_version < '3.12'
|
|
24
|
+
Requires-Dist: cubids>=1.2.1
|
|
25
|
+
Requires-Dist: dcm2bids>=3
|
|
26
|
+
Requires-Dist: dcm2niix>=1.0.20260416
|
|
27
|
+
Requires-Dist: nibabel<5.4,>=5.3; python_version < '3.12'
|
|
28
|
+
Requires-Dist: nibabel>=5.4.2; python_version >= '3.12'
|
|
29
|
+
Requires-Dist: numpy<2
|
|
30
|
+
Requires-Dist: pandas<2.4,>=2
|
|
31
|
+
Requires-Dist: phys2bids>=2.10; python_version < '3.12'
|
|
32
|
+
Requires-Dist: pydicom>=2.4
|
|
33
|
+
Requires-Dist: pyxnat>=1.6
|
|
34
|
+
Requires-Dist: requests>=2
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
|
|
37
|
+
# XNAT CLI for BIDS
|
|
38
|
+
|
|
39
|
+
`xnatbidscli` is a command-line toolkit that takes neuroimaging data from login to analysis-ready dataset: authenticate against an XNAT (Extensible Neuroimaging Archive Toolkit) server, query and download experiments, convert them to BIDS (Brain Imaging Data Structure) with `dcm2bids`, group acquisitions with CuBIDS, map participants/sessions to anonymized IDs, and fold in physiological recordings — all through one CLI built on [PyXNAT](https://pyxnat.github.io/pyxnat/index.html).
|
|
40
|
+
|
|
41
|
+
## User Guide
|
|
42
|
+
|
|
43
|
+
Full documentation for every `xnatbidscli` subcommand, the on-disk layouts each one produces, and how the pieces fit together lives at [xnatbidscli.readthedocs.io](https://xnatbidscli.readthedocs.io/).
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
46
|
+
|
|
47
|
+
Requires Python ≥ 3.11.
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install xnatbidscli
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
See the [Installation guide](https://xnatbidscli.readthedocs.io/installation/) for installing unreleased features from source with uv and the full list of runtime dependencies.
|
|
54
|
+
|
|
55
|
+
## Reporting Issues and Feature Requests
|
|
56
|
+
|
|
57
|
+
Use the [GitHub Issues](https://github.com/nimh-dsst/xnat-bids-cli/issues) feature here to report anything wrong with the CLI, code, or docs. You can also provide feature requests via GitHub Issues.
|
|
58
|
+
|
|
59
|
+
## Attribution
|
|
60
|
+
|
|
61
|
+
Developed and tested primarily by [Eric Earl](https://github.com/ericearl) of the [NIMH Data Science and Sharing Team](https://github.com/nimh-dsst) primarily for the NIMH Intramural Research Program labs. Claude Code and GitHub Copilot were used to develop features, docs, and modifications, as prompted by Eric Earl.
|
|
62
|
+
|
|
63
|
+
## License
|
|
64
|
+
|
|
65
|
+
Distributed under the MIT License.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# XNAT CLI for BIDS
|
|
2
|
+
|
|
3
|
+
`xnatbidscli` is a command-line toolkit that takes neuroimaging data from login to analysis-ready dataset: authenticate against an XNAT (Extensible Neuroimaging Archive Toolkit) server, query and download experiments, convert them to BIDS (Brain Imaging Data Structure) with `dcm2bids`, group acquisitions with CuBIDS, map participants/sessions to anonymized IDs, and fold in physiological recordings — all through one CLI built on [PyXNAT](https://pyxnat.github.io/pyxnat/index.html).
|
|
4
|
+
|
|
5
|
+
## User Guide
|
|
6
|
+
|
|
7
|
+
Full documentation for every `xnatbidscli` subcommand, the on-disk layouts each one produces, and how the pieces fit together lives at [xnatbidscli.readthedocs.io](https://xnatbidscli.readthedocs.io/).
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
Requires Python ≥ 3.11.
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install xnatbidscli
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
See the [Installation guide](https://xnatbidscli.readthedocs.io/installation/) for installing unreleased features from source with uv and the full list of runtime dependencies.
|
|
18
|
+
|
|
19
|
+
## Reporting Issues and Feature Requests
|
|
20
|
+
|
|
21
|
+
Use the [GitHub Issues](https://github.com/nimh-dsst/xnat-bids-cli/issues) feature here to report anything wrong with the CLI, code, or docs. You can also provide feature requests via GitHub Issues.
|
|
22
|
+
|
|
23
|
+
## Attribution
|
|
24
|
+
|
|
25
|
+
Developed and tested primarily by [Eric Earl](https://github.com/ericearl) of the [NIMH Data Science and Sharing Team](https://github.com/nimh-dsst) primarily for the NIMH Intramural Research Program labs. Claude Code and GitHub Copilot were used to develop features, docs, and modifications, as prompted by Eric Earl.
|
|
26
|
+
|
|
27
|
+
## License
|
|
28
|
+
|
|
29
|
+
Distributed under the MIT License.
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
document.addEventListener("DOMContentLoaded", () => {
|
|
2
|
+
const expandAll = document.getElementById("faq-expand-all");
|
|
3
|
+
const collapseAll = document.getElementById("faq-collapse-all");
|
|
4
|
+
const details = document.querySelectorAll("article details");
|
|
5
|
+
|
|
6
|
+
expandAll?.addEventListener("click", () => {
|
|
7
|
+
details.forEach((d) => (d.open = true));
|
|
8
|
+
});
|
|
9
|
+
collapseAll?.addEventListener("click", () => {
|
|
10
|
+
details.forEach((d) => (d.open = false));
|
|
11
|
+
});
|
|
12
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/2.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [2.0.0] - 2026-09-28
|
|
11
|
+
|
|
12
|
+
The project is renamed from `xnatcli` to `xnatbidscli` and is published on PyPI. Downloads are faster and more reliable, and you can now rename subjects and experiments between `query` and `download`.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- The package is set up for PyPI (`pip install xnatbidscli`). The version now comes from git tags, and a GitHub Action publishes each new GitHub release.
|
|
17
|
+
- `download --accession ACCESSION` downloads by one subject ID or label, experiment ID or label, or StudyInstanceUID alone, with no project or subject needed. A subject downloads every experiment for that subject. An experiment downloads only that experiment. A label that matches more than one subject or experiment on the server is an error that lists the matches.
|
|
18
|
+
- `query` filter flags: `--accession` (subject ID or label, experiment ID or label, or StudyInstanceUID), `--date`, `--time`, `--scanner`, `--study`, `--site`, `--operator`, `--sex`, `--handedness` and `--age`. Different flags must all match, and any one value of a flag can match. Text filters match a case-insensitive substring. Experiments with a blank value for a filtered field are dropped.
|
|
19
|
+
- `query` CSVs have new columns at the end: `EXPERIMENT_TIME`, `STUDY_DESCRIPTION`, `STUDY_UID`, `SCANNER_NAME`, `SCANNER_MANUFACTURER`, `SCANNER_MODEL`, `SCANNER_SERIAL`, `SOFTWARE_VERSION`, `FIELD_STRENGTH`, `SITE`, `OPERATOR`, `XNAT_GENDER`, `DICOM_SEX`, `HANDEDNESS` and `AGE`. `XNAT_GENDER` and `DICOM_SEX` both use `M`/`F`/`O` codes, and `--sex` keeps an experiment if either one matches. `AGE`, `EXPERIMENT_TIME`, `STUDY_UID`, `SCANNER_NAME`, `SCANNER_MANUFACTURER`, `SCANNER_MODEL`, `SITE` and `OPERATOR` come from the DICOM header first, with XNAT's value as the fallback.
|
|
20
|
+
- `download --rename-subject` and `--rename-experiment` rename the on-disk `SUBJECT`/`EXPERIMENT` directories in `-1` and `--accession` modes.
|
|
21
|
+
- `query` CSVs have new columns: `SUBJECT_BIDS_RENAME`, `EXPERIMENT_BIDS_RENAME` and `ESTIMATED_SIZE_BYTES`. `download --csv` renames directories using the two rename columns. `ESTIMATED_SIZE_BYTES` is `UNKNOWN`, never `0` or blank, when no size can be determined.
|
|
22
|
+
- `download` shows the bytes downloaded so far for each experiment in `--csv` mode and for a subject `--accession`.
|
|
23
|
+
- `mriconvert` prints an elapsed-time line every 5 seconds while `dcm2bids` runs.
|
|
24
|
+
- `query` shows a status line while it runs, updated every 5 seconds, with the elapsed time and the number of experiments checked and matched. It only appears when stdout is a terminal.
|
|
25
|
+
- `mriconvert_qc.json` records a `LastModified` timestamp for `Dcm2BidsConfigPath`.
|
|
26
|
+
- `mriconvert` backs up an existing `mriconvert_qc.tsv` to `OUTPUT_DIR/mriconvert_qc_backups/PROJECT-<P>_mriconvert_qc_<YYYYMMDD_HHMMSS>.tsv` before overwriting it with different content.
|
|
27
|
+
- `physioconvert` has a new `SKIPPED` status. It skips an association when its output `_physio.tsv.gz` already exists and is valid.
|
|
28
|
+
- Saved credentials at `~/.xnatcli/credentials.cfg` move automatically to `~/.xnatbidscli/credentials.cfg` the first time a command needs them.
|
|
29
|
+
- New docs pages: [Manual Steps](manual.md), [Frequently Asked Questions](faq.md) and [Using Excel](excel.md). The [`query`](cli/query.md), [Manual Steps](manual.md) and [Quickstart](quickstart.md) pages now warn that the query CSV can contain PII, and that unrenamed labels carry it into `download` folder names and logs. There is also a "Project feedback" section on the [Overview](index.md) and a GitHub repository link on every page.
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
|
|
33
|
+
- **Breaking:** The CLI command, Python package and config directory are renamed from `xnatcli` to `xnatbidscli`. Run `pip install xnatbidscli` (or re-run `uv sync` from source) to install the new command. See [Installation](installation.md#upgrading-from-xnatcli).
|
|
34
|
+
- **Breaking:** `physioconvert` needs Python 3.11. The latest `phys2bids` release caps `numpy` below 1.24, which has no builds for Python 3.12 or newer. On Python 3.11, `xnatbidscli` installs everything, including `phys2bids`, and holds `numpy` at 1.23 and `nibabel` below 5.4. On Python 3.12 or newer, `phys2bids` and `bioread` are left out, every other subcommand works, and `physioconvert` exits with a message. See [Installation](installation.md).
|
|
35
|
+
- **Breaking:** `download` now fetches each experiment as whole-experiment zip archives, not one file at a time. Files are saved using XNAT's own scan and resource folder names. The `PARTIAL` status is removed.
|
|
36
|
+
- **Breaking:** `download -n/--ndownload` now sets how many experiments download in parallel. It is not used with `-1`.
|
|
37
|
+
- **Breaking:** `query` output filenames now end in a `_<YYYYMMDD_HHMMSS>` timestamp, so a new run no longer overwrites an old file.
|
|
38
|
+
- **Breaking:** The `query` CSV has a new column order: `PROJECT,SUBJECT_LABEL,SUBJECT_ID,SUBJECT_BIDS_RENAME,EXPERIMENT_LABEL,EXPERIMENT_ID,EXPERIMENT_DATE,EXPERIMENT_BIDS_RENAME,ESTIMATED_SIZE_BYTES`, followed by the new metadata columns listed above.
|
|
39
|
+
- **Breaking:** The log CSVs from `download`, `mriconfig`, `mriconvert`, `physioconvert` and `cubids` have a new `USER` column after `DATESTAMP`.
|
|
40
|
+
- `query` creates its CSV with mode `rw-------` (owner only) on Linux and macOS, since it can hold PII such as MRNs, scan dates and ages. It then prints an `INFO:` line explaining that sharing the CSV requires changing its group and permissions.
|
|
41
|
+
- `query` now finishes with `Took N second(s) to write N row(s) to ...` instead of `Wrote N row(s) to ...`.
|
|
42
|
+
- `query` makes one REST call per subject and three per experiment (record, DICOM header, size), so it is slower on large projects. Filters skip the later calls for experiments they drop.
|
|
43
|
+
- `mriconvert` uses `sub-<label>`/`ses-<label>` directory names exactly as they are when `download` has already renamed them.
|
|
44
|
+
- `download` Ctrl+C with `-n` > 1: experiments that have not started are cancelled, and the command exits right away.
|
|
45
|
+
|
|
46
|
+
### Fixed
|
|
47
|
+
|
|
48
|
+
- `download` is more stable, especially for session-level resources. It saves a single-file resource correctly when XNAT sends the file without a zip.
|
|
49
|
+
- `download` now reports a dropped connection clearly, instead of showing a generic error.
|
|
50
|
+
- When `physioconvert` runs in parallel, lines from different workers no longer get mixed together in the log.
|
|
51
|
+
|
|
52
|
+
## [1.0.0] - 2026-07-15
|
|
53
|
+
|
|
54
|
+
First release.
|
|
55
|
+
|
|
56
|
+
### Added
|
|
57
|
+
|
|
58
|
+
- `xnatcli` subcommands: `login`, `query`, `download`, `mriconfig`, `mriconvert`, `physioconvert`, `bidsmap` and `cubids`.
|
|
59
|
+
- A documentation site built with Zensical and hosted on Read the Docs.
|
|
60
|
+
|
|
61
|
+
[Unreleased]: https://github.com/nimh-dsst/xnat-bids-cli/compare/v2.0.0...HEAD
|
|
62
|
+
[2.0.0]: https://github.com/nimh-dsst/xnat-bids-cli/compare/v1.0.0...v2.0.0
|
|
63
|
+
[1.0.0]: https://github.com/nimh-dsst/xnat-bids-cli/releases/tag/v1.0.0
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# `xnatbidscli bidsmap`
|
|
2
|
+
|
|
3
|
+
Generates a participant/session mapping TSV for a BIDS dataset — the output of `xnatbidscli mriconvert` (with any physio already placed by [`xnatbidscli physioconvert`](physioconvert.md)) — at `INPUT_DIR/PROJECT/`. The map is later filled in by hand to relate XNAT IDs and real dates to anonymized BIDS IDs and session codenames. When `-o OUTPUT_DIR` is provided, it additionally applies all filled-in renames by copying the BIDS dataset to a new directory tree.
|
|
4
|
+
|
|
5
|
+
This is the "map" half of the xnatbidscli workflow: `mriconvert`/`physioconvert` first **convert** raw source data to BIDS, preserving the source data untouched; `bidsmap` then **maps** that raw/unmapped BIDS data to a separate, renamed BIDS output, so the intermediary unmapped BIDS data is preserved too. `bidsmap` operates on `.nii.gz` main files with `.json`/`.bval`/`.bvec` sidecars, reading its `rename` column and QC-exclusion columns (`recommend_for_use`, `complete`, `usable`, `qc_rating`) from `mriconvert_qc.tsv` (one row per `.nii.gz` file, so `rename` unambiguously targets one file). A physio `_physio.tsv.gz`/`.json` pair co-located under the same `sub-*/ses-*/<datatype>/` directory rides along the copy for free (participant/session label substitution only — [`physioconvert`](physioconvert.md) already writes it under its final name, so no separate rename step is needed for it).
|
|
6
|
+
|
|
7
|
+
`mriconvert_qc.tsv` is named distinctly from BIDS's canonical `scans.tsv` (see [`xnatbidscli mriconvert`](mriconvert.md)); `bidsmap -o` promotes it to the canonical `scans.tsv`/`scans.json` in the mapped output.
|
|
8
|
+
|
|
9
|
+
## Map TSV generation (always runs)
|
|
10
|
+
|
|
11
|
+
1. Validates that `--input` exists and that the BIDS dataset `INPUT_DIR/PROJECT/` exists.
|
|
12
|
+
2. Scans `INPUT_DIR/PROJECT/` for `sub-*` directories and, within each, `ses-*` subdirectories.
|
|
13
|
+
3. Writes `INPUT_DIR/PROJECT-<PROJECT>_bidsmap.tsv` with the columns `participant_id`, `participant_rename`, `session_id`, `session_rename`. One row is emitted per `(participant, session)` pair, with the two `*_rename` columns left blank for later editing. Rows are sorted alphanumerically by `participant_id` then `session_id`.
|
|
14
|
+
- If the dataset has **no** sessions (no participant has any `ses-*` subdirectory), only the `participant_id` and `participant_rename` columns are written, one row per participant.
|
|
15
|
+
- If the dataset uses sessions but a particular participant has no `ses-*` subdirectory, that participant is skipped with a warning.
|
|
16
|
+
4. If `PROJECT-<PROJECT>_bidsmap.tsv` already exists, a fresh blank map is generated and compared to it (with `pandas`): any `(participant_id, session_id)` pairs not already present are appended, and all existing rows — including any `*_rename` values already filled in — are preserved. The merged table is re-sorted and rewritten.
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
xnatbidscli bidsmap -i MRICONVERT_OUTPUT_DIR -p PROJECT
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Copy-with-rename (`-o OUTPUT_DIR`)
|
|
23
|
+
|
|
24
|
+
When `-o` is provided, after updating the map TSV the command reads back the renames and writes a fully renamed copy of the BIDS dataset to `OUTPUT_DIR/PROJECT/`:
|
|
25
|
+
|
|
26
|
+
- **`PROJECT-<PROJECT>_bidsmap.tsv`** — `participant_rename` and `session_rename` columns rename `sub-*` and `ses-*` directory names and the matching labels embedded in all filenames. Blank values mean "keep the original label."
|
|
27
|
+
- **`mriconvert_qc.tsv`** — its `rename` column supplies a corrected `bids_name` (the part after `sub-X[_ses-Y]_`) for the file(s) that row describes. Sidecar files (`.json`, `.bval`, `.bvec`) sharing the same stem are renamed to match. Blank values mean "keep the original bids_name."
|
|
28
|
+
|
|
29
|
+
The copy also:
|
|
30
|
+
|
|
31
|
+
- **QC filtering**: Rows whose `recommend_for_use`, `complete`, or `usable` is exactly `"FALSE"`, or whose `qc_rating` is exactly `"FAIL"` or `"UNCERTAIN"`, have their file(s) excluded from the copy (along with sidecars) and their row omitted from the output manifest. Values in any of these columns that are non-empty but do not match a valid Level from `mriconvert_qc.json` (e.g. `"false"` instead of `"FALSE"`) generate an additional warning, since they are silently ignored by the filter.
|
|
32
|
+
- Updates `participants.tsv` in the output with the renamed participant IDs, and writes `scans.tsv` (`filename`, `bids_name`, `participant_id`, `session_id` columns, among others) to reflect all renames, omits rows for QC-excluded files, and drops the columns `rename` and `physio` (both have already been applied by the time `bidsmap -o` runs — `rename` to `bids_name`, `physio` by `xnatbidscli physioconvert`, which must run before `bidsmap -o`). All other reviewer columns are preserved. `mriconvert_qc.tsv`/`mriconvert_qc.json` and `physioconvert_qc.tsv`/`.json` themselves are **not** copied — `mriconvert_qc.tsv`/`.json` are promoted to `scans.tsv`/`.json` instead, and `physioconvert_qc.tsv`/`.json` stay raw-tree-only bookkeeping with no promoted counterpart.
|
|
33
|
+
- Skips `tmp_dcm2bids` and `log` scratch directories.
|
|
34
|
+
- **Incremental by default**: if `OUTPUT_DIR/PROJECT/` already exists, files under `sub-*/` whose destination path already exists are treated as already mapped and left untouched — only files not yet present at the destination are copied. Root-level manifests (`scans.tsv`, `participants.tsv`, `dataset_description.json`, ...) are always re-copied/re-written and re-patched, since they reflect the fully merged source state. This lets `bidsmap -o` be re-run safely as new data lands in `INPUT_DIR/PROJECT/` (e.g. from further `mriconvert`/`physioconvert` runs).
|
|
35
|
+
- **Warns loudly** when new files are being mapped into a `sub-*/[ses-*/]` directory that already existed at the destination before this run, since that session was already mapped and is only gaining files.
|
|
36
|
+
- Warns loudly for any two source files that would map to the same destination path (neither is copied); all warnings are re-displayed together at the end.
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
xnatbidscli bidsmap -i MRICONVERT_OUTPUT_DIR -p PROJECT -o RENAMED_OUTPUT_DIR
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
For example, if the BIDS dataset lives at `/data/bids/MYPROJ/`, then:
|
|
43
|
+
|
|
44
|
+
- `xnatbidscli bidsmap -i /data/bids -p MYPROJ` writes `/data/bids/PROJECT-MYPROJ_bidsmap.tsv`.
|
|
45
|
+
- After filling in the rename columns, `xnatbidscli bidsmap -i /data/bids -p MYPROJ -o /data/renamed` copies the dataset to `/data/renamed/MYPROJ/` with all renames applied.
|
|
46
|
+
|
|
47
|
+
| Argument | Description |
|
|
48
|
+
| --- | --- |
|
|
49
|
+
| `-i`, `--input` | **Required.** Root directory holding the BIDS dataset at `INPUT_DIR/PROJECT/`. The map TSV is written here as `PROJECT-<PROJECT>_bidsmap.tsv`. |
|
|
50
|
+
| `-p`, `--project` | **Required.** Project directory name under `INPUT_DIR` identifying the BIDS dataset to scan. |
|
|
51
|
+
| `-o`, `--output` | *Optional.* When provided, copy the BIDS dataset to `OUTPUT_DIR/PROJECT/` with all renames from the map TSV and `mriconvert_qc.tsv`'s own `rename` column applied. If `OUTPUT_DIR/PROJECT/` already exists, only files not already mapped there are copied (see above). |
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# `xnatbidscli cubids`
|
|
2
|
+
|
|
3
|
+
Runs [`CuBIDS`](https://cubids.readthedocs.io/) on a BIDS dataset produced by `xnatbidscli mriconvert` — first `cubids add-nifti-info` (which annotates JSON sidecars with NIfTI header fields) and then `cubids group` (which groups acquisitions by their parameters and writes `_summary.tsv`, `_files.tsv`, `_AcqGrouping.tsv`, and `_AcqGroupInfo.txt`).
|
|
4
|
+
|
|
5
|
+
1. Validates that `--input` is an existing directory and that `INPUT_DIR/<PROJECT>/` (the BIDS dataset) exists. The expected layout is the one produced by `xnatbidscli mriconvert` — `<input>/PROJECT/sub-X/ses-Y/...`.
|
|
6
|
+
2. Verifies that `cubids` is on `PATH`; exits with an error if it is missing.
|
|
7
|
+
3. Creates the output directory `INPUT_DIR/PROJECT-<PROJECT>_cubids/` if it does not already exist. If it does, the directory is reused (CuBIDS writes its own outputs into it).
|
|
8
|
+
4. If `INPUT_DIR/<PROJECT>/tmp_dcm2bids/` exists (leftover dcm2bids scratch), it is moved out to `INPUT_DIR/.<PROJECT>_cubids_stash_tmp_dcm2bids/` for the duration of the run so CuBIDS does not scan it, and moved back when the run finishes (success or failure). CuBIDS has no built-in ignore mechanism; it walks the whole BIDS tree.
|
|
9
|
+
5. Invokes `cubids add-nifti-info <bids_dir>` without `--use-datalad` (datalad is disabled by default in CuBIDS), so the BIDS dataset itself is mutated in place to add NIfTI header info to sidecars.
|
|
10
|
+
6. Invokes `cubids group <bids_dir> v0`, which writes `v0_summary.tsv`, `v0_files.tsv`, `v0_AcqGrouping.tsv`, and `v0_AcqGroupInfo.txt` into `INPUT_DIR/<PROJECT>/code/CuBIDS/`.
|
|
11
|
+
7. On a successful `group`, the `INPUT_DIR/<PROJECT>/code/CuBIDS/` directory is merged into `INPUT_DIR/PROJECT-<PROJECT>_cubids/CuBIDS/` (existing files with the same name are overwritten; unrelated files in the destination are left alone) and the source is removed. If `INPUT_DIR/<PROJECT>/code/` is empty afterwards, it is also removed.
|
|
12
|
+
8. If `add-nifti-info` exits non-zero, `group` is skipped and the command exits `1`. Otherwise the exit code is `0` if both steps succeeded and `1` if `group` failed.
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
xnatbidscli cubids -i BIDSCONVERT_OUTPUT_DIR -p PROJECT
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
For example, if you ran `xnatbidscli mriconvert -i DOWNLOAD_DIR -p MYPROJ -o /data/bids -c config.json`, the BIDS dataset lives at `/data/bids/MYPROJ/`, and `xnatbidscli cubids -i /data/bids -p MYPROJ` writes CuBIDS outputs to `/data/bids/PROJECT-MYPROJ_cubids/CuBIDS/v0_*.tsv`.
|
|
19
|
+
|
|
20
|
+
| Argument | Description |
|
|
21
|
+
| --- | --- |
|
|
22
|
+
| `-i`, `--input` | **Required.** Parent directory holding the BIDS dataset at `INPUT_DIR/PROJECT/` (i.e., the output of `xnatbidscli mriconvert`). The CuBIDS output subdirectory is created here. |
|
|
23
|
+
| `-p`, `--project` | **Required.** Project directory name under `INPUT_DIR` identifying the BIDS dataset to process. |
|
|
24
|
+
| `-l`, `--log` | *Optional.* Write a per-step log CSV to `INPUT_DIR/PROJECT-<PROJECT>_cubids/log/cubids_<YYYYMMDD_HHMMSS>_log.csv` with header `DATESTAMP,USER,PROJECT,STEP,STATUS`. One row per CuBIDS step (`add-nifti-info`, `group`), each with `STATUS` of `COMPLETE` or `FAILURE`. |
|