Metadata-Version: 2.4
Name: xnatctl
Version: 0.2.6
Summary: Modern CLI for XNAT neuroimaging server administration
Project-URL: homepage, https://github.com/rickyltwong/xnatctl
Project-URL: repository, https://github.com/rickyltwong/xnatctl.git
Project-URL: documentation, https://xnatctl.readthedocs.io
Author-email: Ricky Wong <rickywonglt15@outlook.com>
License: MIT
License-File: LICENSE
Keywords: cli,dicom,medical-imaging,neuroimaging,xnat
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Healthcare Industry
Classifier: Intended Audience :: Science/Research
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
Classifier: Topic :: System :: Systems Administration
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: click>=8.1.0
Requires-Dist: defusedxml>=0.7.1
Requires-Dist: httpx>=0.25.0
Requires-Dist: pydantic>=2.0.0
Requires-Dist: python-dotenv>=1.0.0
Requires-Dist: pyyaml>=6.0
Requires-Dist: rich>=13.0.0
Provides-Extra: dev
Requires-Dist: mypy>=1.8.0; extra == 'dev'
Requires-Dist: pre-commit>=3.7.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
Requires-Dist: pytest-mock>=3.12.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: ruff>=0.4.0; extra == 'dev'
Requires-Dist: types-pyyaml>=6.0.0; extra == 'dev'
Provides-Extra: dicom
Requires-Dist: pydicom>=2.4.0; extra == 'dicom'
Requires-Dist: pynetdicom>=2.0.0; extra == 'dicom'
Provides-Extra: docs
Requires-Dist: furo>=2024.1.0; extra == 'docs'
Requires-Dist: myst-parser>=3.0.0; extra == 'docs'
Requires-Dist: sphinx-copybutton>=0.5.0; extra == 'docs'
Requires-Dist: sphinx>=7.0; extra == 'docs'
Description-Content-Type: text/markdown

# xnatctl

A modern command-line interface for XNAT neuroimaging server administration.

## What is xnatctl?

xnatctl is a command-line tool for managing neuroimaging data on XNAT servers.[^xnat]
It lets you browse projects and subjects, download and upload imaging sessions,
run processing pipelines, and perform administrative tasks -- all from your
terminal. Whether you are a researcher downloading data for analysis or a system
administrator managing hundreds of subjects, xnatctl provides a consistent,
scriptable interface to your XNAT server.

## Features

- **Resource-centric commands** -- interact with XNAT the way you think about
  it: `xnatctl project list`, `xnatctl session download`, `xnatctl scan show`.
  Every command follows the pattern `xnatctl <resource> <action> [args]`.

- **Profile-based configuration** -- manage multiple XNAT servers with named
  profiles and switch between them instantly. Keep separate profiles for
  production, development, and collaboration servers in a single config file.

- **Consistent output formats** -- resource-oriented commands support
  `--output json|table` and `--quiet` (IDs only), so you can pipe results into
  scripts or read them in a human-friendly table without changing your
  workflow.

- **Parallel operations** -- batch uploads and downloads run across multiple
  workers with real-time progress tracking. Large transfers stay fast without
  extra scripting.

- **Session authentication** -- log in once with `xnatctl auth login` and your
  session token is cached locally. Expired tokens are refreshed automatically,
  so you stay authenticated without repeated prompts.

- **Pure HTTP** -- xnatctl talks directly to the XNAT REST API using httpx.
  Existing Python libraries like [pyxnat](https://pyxnat.github.io/pyxnat/) and
  [xnatpy](https://xnat.readthedocs.io/) inspired this project, but they are
  excellent *Python libraries* intended to be imported into your own code. xnatctl
  exists for the complementary use case: a **CLI-first** workflow where you want to
  explore resources, automate API interactions from shell scripts, and run common
  administrative tasks without writing a bespoke Python program.

  The command structure and UX borrow from tools like `kubectl` and `airflowctl`:
  resource-centric subcommands, consistent flags, and output you can read as a human
  or pipe into other tools. xnatctl ships as a standalone CLI that can be installed
  as a single binary (no Python environment required).

## Installation

### Standalone Binary (no Python required)

If you do not have Python installed or prefer a single executable, download a
pre-built binary. On **Linux and macOS**, the install script auto-detects your
OS and architecture:

```bash
# One-line install (Linux/macOS only, auto-detects platform)
curl -fsSL https://github.com/rickyltwong/xnatctl/raw/main/install.sh | bash

# Install a specific version
XNATCTL_VERSION=v0.1.0 curl -fsSL https://github.com/rickyltwong/xnatctl/raw/main/install.sh | bash

# Custom install directory (default: ~/.local/bin)
XNATCTL_INSTALL_DIR=/usr/local/bin curl -fsSL https://github.com/rickyltwong/xnatctl/raw/main/install.sh | bash
```

Or download manually from [GitHub Releases](https://github.com/rickyltwong/xnatctl/releases):

| Platform       | Asset                              |
|----------------|------------------------------------|
| Linux (x86_64) | `xnatctl-linux-amd64.tar.gz`      |
| macOS (x86_64) | `xnatctl-darwin-amd64.tar.gz`     |
| Windows (x86_64) | `xnatctl-windows-amd64.zip`     |

**Linux / macOS:**

```bash
tar -xzf xnatctl-<platform>-amd64.tar.gz
chmod +x xnatctl
mv xnatctl ~/.local/bin/
```

**Windows (PowerShell):**

```powershell
Expand-Archive xnatctl-windows-amd64.zip -DestinationPath .
New-Item -ItemType Directory -Force -Path "$env:LOCALAPPDATA\bin"
Move-Item xnatctl.exe "$env:LOCALAPPDATA\bin\"
```

> **Note:** On Windows, make sure `%LOCALAPPDATA%\bin` is on your PATH.
> You can add it via Settings > System > About > Advanced system settings >
> Environment Variables, or see the [Installation guide](docs/installation.rst)
> for a PowerShell command.

### Python Package

If you already have Python 3.11+ and want to install xnatctl as a package,
use pip or uv:

```bash
# From PyPI (recommended)
pip install xnatctl

# With uv
uv pip install xnatctl

# For DICOM utilities (optional -- adds pydicom and pynetdicom)
pip install "xnatctl[dicom]"

# From source
pip install git+https://github.com/rickyltwong/xnatctl.git
```

### Docker

For containerized environments or CI pipelines where you want to avoid local
installation entirely:

```bash
docker run --rm ghcr.io/rickyltwong/xnatctl:main --help
```

For full installation instructions including shell completion and
troubleshooting, see the [Installation guide](docs/installation.rst).

## Quick Start

Once installed, you can be up and running in four steps.

**1. Create a configuration file.** This stores your XNAT server URL and
default settings so you do not have to pass them on every command:

```bash
xnatctl config init --url https://xnat.example.org
```

**2. Authenticate.** Log in with your XNAT credentials. The session token is
cached locally, so subsequent commands authenticate automatically:

```bash
xnatctl auth login
```

**3. Browse your data.** List the projects you have access to and inspect their
contents:

```bash
xnatctl project list
```

**4. Download a session.** Pull imaging data to your local machine for analysis.
Use an experiment accession number or, if you have a default project set, a
session label:

```bash
xnatctl session download -E XNAT_E00001 --out ./data
```

For a detailed walkthrough, see the [Quick Start guide](docs/quickstart.rst).

## Commands

| Command              | Description                                      |
|----------------------|--------------------------------------------------|
| `xnatctl config`    | Manage configuration profiles                    |
| `xnatctl auth`      | Authentication (login/logout/status)             |
| `xnatctl project`   | Project operations (list/show/create)            |
| `xnatctl subject`   | Subject operations (list/show/rename/delete)     |
| `xnatctl session`   | Session operations (list/show/download/upload)   |
| `xnatctl scan`      | Scan operations (list/show/delete/download)      |
| `xnatctl resource`  | Resource operations (list/upload/download)       |
| `xnatctl prearchive` | Prearchive management (list/archive/delete/move) |
| `xnatctl pipeline`  | Pipeline execution (list/run/status/cancel)      |
| `xnatctl admin`     | Administrative operations (users/catalogs/audit) |
| `xnatctl api`       | Raw API access (escape hatch for any endpoint)   |
| `xnatctl local`     | Offline operations (extract downloaded ZIPs)     |
| `xnatctl dicom`     | DICOM utilities (requires `xnatctl[dicom]`)      |

For complete usage and examples, see the [CLI Reference](docs/cli-reference.rst).

## Configuration

Config file location: `~/.config/xnatctl/config.yaml`

```yaml
default_profile: production
output_format: table

profiles:
  production:
    url: https://xnat.example.org
    username: myuser          # optional -- can also use env vars
    password: mypassword      # optional -- can also use env vars
    verify_ssl: true
    timeout: 30
    default_project: MYPROJECT

  development:
    url: https://xnat-dev.example.org
    verify_ssl: false
```

### Working with Profiles

Profiles let you store connection details for each XNAT server you work with.
You can create, add, and switch profiles from the command line:

```bash
# Create an initial config (prompts for URL and optional defaults)
xnatctl config init --url https://xnat.example.org

# Add additional profiles
xnatctl config add-profile dev --url https://xnat-dev.example.org --no-verify-ssl

# Switch the active profile
xnatctl config use-context dev

# Show the active profile and config
xnatctl config show
```

### Authentication Flow

Log in once and your session token is cached. xnatctl reuses the cached token
and refreshes it automatically when it expires:

```bash
# Login and cache a session token
xnatctl auth login

# Check current user and session context
xnatctl whoami
```

Credential priority (highest to lowest):

1. CLI arguments (`--username`, `--password`)
2. Environment variables (`XNAT_USER`, `XNAT_PASS`)
3. Profile config (`username`, `password` in config.yaml)
4. Interactive prompt

Session tokens are cached at `~/.config/xnatctl/.session` and used
automatically until they expire.

### Environment Variables

You can override any profile setting with environment variables. This is
especially useful for CI pipelines and non-interactive scripts:

| Variable        | Description                                          |
|-----------------|------------------------------------------------------|
| `XNAT_URL`     | Server URL                                           |
| `XNAT_USER`    | Username                                             |
| `XNAT_PASS`    | Password                                             |
| `XNAT_TOKEN`   | Session token (highest auth priority)                |
| `XNAT_PROFILE` | Config profile name                                  |

Notes:

- `XNAT_TOKEN` takes precedence over cached sessions and username/password
  credentials. Use it when you already have a valid token from another tool.
- `XNAT_URL` and `XNAT_PROFILE` override values from `config.yaml` for the
  current shell session.
- Use `XNAT_USER` and `XNAT_PASS` for non-interactive authentication in CI
  jobs and automated scripts.

## Documentation

Complete documentation is available in the [docs/](docs/) directory. Topics
include installation, key concepts, configuration, CLI reference, downloading,
uploading, workflows, and XNAT compatibility.

## Development

```bash
# Clone and install
git clone https://github.com/rickyltwong/xnatctl.git
cd xnatctl
uv sync --dev

# Run tests
uv run pytest tests/ -v

# Lint and format
uv run ruff check xnatctl scripts
uv run ruff format xnatctl scripts

# Type check
uv run mypy xnatctl
```

## License

MIT

[^xnat]: XNAT is an open source project produced by NRG at the Washington University School of Medicine. See `https://xnat.org/`.
