Core API¶
The core package provides foundational classes for XNAT server communication, configuration management, authentication, and error handling.
Client¶
The XNATClient class is the primary HTTP client for all XNAT REST API operations.
It provides automatic retry logic, session management, pagination support, and
connection pooling.
Key Features:
Automatic retry with exponential backoff for transient errors (502, 503, 504)
Session-based authentication with token caching
Pagination support for large result sets
SSL verification control
Context manager support for automatic cleanup
Connection pooling via httpx
Basic Usage:
from xnatctl.core.client import XNATClient
# Create and authenticate client
client = XNATClient(
base_url="https://xnat.example.org",
username="admin",
password="secret",
timeout=60,
verify_ssl=True
)
client.authenticate()
# Make API calls
response = client.get("/data/projects")
# Use as context manager
with XNATClient(base_url="https://xnat.example.org") as client:
client.authenticate()
data = client.get("/data/projects")
Class Reference:
- class xnatctl.core.client.XNATClient(base_url, username=None, password=None, session_token=None, timeout=21600, max_retries=3, verify_ssl=True, auto_reauth=False)[source]¶
HTTP client for XNAT REST API with retry and pagination.
- authenticate()[source]¶
Authenticate with username/password and get JSESSIONID.
- Returns:
Session token (JSESSIONID).
- Raises:
AuthenticationError – If authentication fails.
- Return type:
- post(path, *, params=None, json=None, data=None, files=None, headers=None, timeout=None)[source]¶
POST request.
- put(path, *, params=None, json=None, data=None, files=None, headers=None, timeout=None)[source]¶
PUT request.
- paginate(path, *, params=None, page_size=100, result_key='ResultSet.Result')[source]¶
Paginated GET returning items one by one.
- ping()[source]¶
Check server connectivity and get version info.
- Returns:
Dict with server info.
- Raises:
NetworkError – If server is unreachable.
- Return type:
- whoami()[source]¶
Get current user information.
- Returns:
Dict with user info.
- Raises:
AuthenticationError – If not authenticated.
- Return type:
- __init__(base_url, username=None, password=None, session_token=None, timeout=21600, max_retries=3, verify_ssl=True, auto_reauth=False)¶
Config¶
Configuration management with YAML file support and environment variable overrides. Supports multiple server profiles for different XNAT environments.
Configuration File Location:
~/.config/xnatctl/config.yaml(default)
Profile Structure:
Each profile defines connection parameters for one XNAT server:
default_profile: production
output_format: table
profiles:
production:
url: https://xnat.example.org
username: admin
verify_ssl: true
timeout: 30
default_project: MYPROJECT
Credential Resolution:
The Config class resolves credentials in this priority order:
Environment variables (
XNAT_URL,XNAT_USER,XNAT_PASS)Config file profile settings
Default values
Class Reference:
- class xnatctl.core.config.Config(default_profile='default', output_format='table', profiles=<factory>)[source]¶
Application configuration.
- classmethod load(config_path=None)[source]¶
Load config from file with environment variable overrides.
Priority (highest to lowest): 1. Environment variables 2. Config file 3. Defaults
- save(config_path=None)[source]¶
Save config to file (excludes secrets).
- Parameters:
config_path (Path | None) – Optional path to config file.
- get_profile(name=None)[source]¶
Get profile by name or default.
- Parameters:
name (str | None) – Profile name. If None, uses default_profile.
- Returns:
Profile configuration.
- Raises:
ProfileNotFoundError – If profile doesn’t exist.
- Return type:
- add_profile(name, url, verify_ssl=True, timeout=21600, default_project=None)[source]¶
Add or update a profile.
- set_default_profile(name)[source]¶
Set the default profile.
- Parameters:
name (str) – Profile name to set as default.
- Raises:
ProfileNotFoundError – If profile doesn’t exist.
Authentication¶
Session-based authentication with token caching. Handles login, logout, and session validation.
Session Token Storage:
Cached at
~/.config/xnatctl/.sessionper profileAutomatically reused until expiration
Can be overridden with
XNAT_TOKENenvironment variable
Authentication management for xnatctl.
Handles credential storage and session token caching.
- class xnatctl.core.auth.CachedSession(token, url, username, created_at, expires_at=None)[source]¶
Cached session token with metadata.
- class xnatctl.core.auth.AuthManager(cache_file=None)[source]¶
Manages authentication credentials and session tokens.
- get_token_from_env()[source]¶
Get session token from environment variable.
- Returns:
Token if set.
- Return type:
str | None
- save_session(token, url, username, expiry_minutes=15)[source]¶
Save session token to cache.
- Parameters:
- Returns:
Cached session object.
- Return type:
- load_session(url=None)[source]¶
Load cached session token.
- Parameters:
url (str | None) – Optional URL to match. If provided, only returns session for that URL.
- Returns:
Cached session if valid, None otherwise.
- Return type:
CachedSession | None
Exceptions¶
Comprehensive exception hierarchy for error handling.
Exception Hierarchy:
XNATCtlError (base)
├── ConfigurationError
│ └── ProfileNotFoundError
├── AuthenticationError
├── ValidationError
├── NetworkError
│ ├── ConnectionError
│ ├── ServerUnreachableError
│ ├── RetryExhaustedError
│ └── TimeoutError
└── ResourceNotFoundError
Usage Example:
from xnatctl.core.client import XNATClient
from xnatctl.core.exceptions import (
AuthenticationError,
ResourceNotFoundError,
NetworkError
)
try:
client = XNATClient(base_url="https://xnat.example.org")
client.authenticate()
except AuthenticationError:
print("Invalid credentials")
except NetworkError:
print("Cannot reach server")
except ResourceNotFoundError as e:
print(f"Resource not found: {e.resource_type} {e.resource_id}")
Exception hierarchy for xnatctl.
Provides typed exceptions for different failure modes with clear error messages.
- exception xnatctl.core.exceptions.XNATCtlError(message, details=None)[source]¶
Bases:
ExceptionBase exception for all xnatctl errors.
- exception xnatctl.core.exceptions.ConfigurationError(message, field=None, value=None)[source]¶
Bases:
XNATCtlErrorError in configuration (missing, invalid, or malformed).
- exception xnatctl.core.exceptions.ProfileNotFoundError(profile)[source]¶
Bases:
ConfigurationErrorRequested profile does not exist.
- exception xnatctl.core.exceptions.ValidationError(message, field=None, value=None)[source]¶
Bases:
XNATCtlErrorInput validation failed.
- exception xnatctl.core.exceptions.InvalidURLError(url, reason='')[source]¶
Bases:
ValidationErrorInvalid URL format.
- exception xnatctl.core.exceptions.InvalidPortError(port)[source]¶
Bases:
ValidationErrorInvalid port number.
- exception xnatctl.core.exceptions.InvalidIdentifierError(identifier_type, value, reason='')[source]¶
Bases:
ValidationErrorInvalid XNAT identifier (project, subject, session, scan).
- exception xnatctl.core.exceptions.PathValidationError(path, reason)[source]¶
Bases:
ValidationErrorPath validation failed.
- exception xnatctl.core.exceptions.ConnectionError(message, url=None)[source]¶
Bases:
XNATCtlErrorBase class for connection-related errors.
- exception xnatctl.core.exceptions.NetworkError(url, cause=None)[source]¶
Bases:
ConnectionErrorNetwork-level error (DNS, TCP, TLS).
- exception xnatctl.core.exceptions.ServerUnreachableError(url)[source]¶
Bases:
ConnectionErrorServer is not reachable.
- exception xnatctl.core.exceptions.TimeoutError(url, timeout)[source]¶
Bases:
ConnectionErrorRequest timed out.
- exception xnatctl.core.exceptions.RetryExhaustedError(operation, attempts, last_error=None)[source]¶
Bases:
ConnectionErrorAll retry attempts failed.
- exception xnatctl.core.exceptions.AuthenticationError(url=None, reason='')[source]¶
Bases:
XNATCtlErrorAuthentication failed.
- exception xnatctl.core.exceptions.SessionExpiredError(url=None)[source]¶
Bases:
AuthenticationErrorSession has expired.
- exception xnatctl.core.exceptions.PermissionDeniedError(resource, operation='access', url=None)[source]¶
Bases:
AuthenticationErrorUser lacks permission for the requested operation.
- exception xnatctl.core.exceptions.ResourceError(message, resource_type=None, resource_id=None)[source]¶
Bases:
XNATCtlErrorError related to XNAT resources.
- exception xnatctl.core.exceptions.ResourceNotFoundError(resource_type, resource_id)[source]¶
Bases:
ResourceErrorRequested resource does not exist.
- exception xnatctl.core.exceptions.ResourceExistsError(resource_type, resource_id)[source]¶
Bases:
ResourceErrorResource already exists.
- exception xnatctl.core.exceptions.OperationError(operation, message, details=None)[source]¶
Bases:
XNATCtlErrorError during an operation.
- exception xnatctl.core.exceptions.UploadError(message, file_path=None, details=None)[source]¶
Bases:
OperationErrorError during upload.
- exception xnatctl.core.exceptions.DownloadError(message, resource=None, details=None)[source]¶
Bases:
OperationErrorError during download.
- exception xnatctl.core.exceptions.BatchOperationError(operation, succeeded, failed, errors)[source]¶
Bases:
OperationErrorError in batch operation with partial success.
- exception xnatctl.core.exceptions.DicomError(message, file_path=None)[source]¶
Bases:
XNATCtlErrorError related to DICOM operations.
- exception xnatctl.core.exceptions.DicomParseError(file_path, reason='')[source]¶
Bases:
DicomErrorFailed to parse DICOM file.
- exception xnatctl.core.exceptions.DicomStoreError(message, host=None, port=None)[source]¶
Bases:
DicomErrorDICOM C-STORE operation failed.
- exception xnatctl.core.exceptions.TransferError(message, details=None)[source]¶
Bases:
OperationErrorError during project transfer.
- exception xnatctl.core.exceptions.TransferConflictError(entity_type, local_id, remote_id, reason)[source]¶
Bases:
TransferErrorConflict detected on destination during transfer.
- exception xnatctl.core.exceptions.TransferCircuitBreakerError(failures, max_failures)[source]¶
Bases:
TransferErrorToo many consecutive transfer failures.
- exception xnatctl.core.exceptions.TransferVerificationError(entity_id, expected, actual)[source]¶
Bases:
TransferErrorPost-transfer verification failed.
- exception xnatctl.core.exceptions.TransferConfigError(message, field=None)[source]¶
Bases:
TransferErrorInvalid transfer configuration.
Validation¶
Input validation utilities for XNAT resource identifiers, URLs, and parameters.
Validators:
validate_server_url(url: str) -> str- Normalize and validate XNAT server URLsvalidate_project_id(project_id: str) -> None- Validate project ID formatvalidate_subject_label(label: str) -> None- Validate subject label formatvalidate_session_label(label: str) -> None- Validate session label format
Input validation module for xnatctl.
Provides comprehensive validation for URLs, ports, identifiers, paths, and DICOM-specific values.
- xnatctl.core.validation.validate_server_url(url)[source]¶
Validate XNAT server URL and return normalized form.
- Parameters:
url (str) – Server URL to validate.
- Returns:
Normalized URL (trailing slash removed).
- Raises:
InvalidURLError – If URL is malformed or uses unsupported scheme.
- Return type:
- xnatctl.core.validation.validate_url_or_none(url)[source]¶
Validate URL if provided, or return None.
- xnatctl.core.validation.validate_port(port, allow_none=False)[source]¶
Validate port number.
- Parameters:
- Returns:
Validated port number or None.
- Raises:
InvalidPortError – If port is invalid.
- Return type:
int | None
- xnatctl.core.validation.validate_xnat_identifier(value, identifier_type='identifier', *, allow_empty=False, max_length=64)[source]¶
Validate an XNAT identifier (project, subject, session, scan ID).
- Parameters:
- Returns:
Validated and stripped identifier.
- Raises:
InvalidIdentifierError – If identifier is invalid.
- Return type:
- xnatctl.core.validation.validate_scan_id(scan_id)[source]¶
Validate XNAT scan ID (typically numeric but XNAT allows strings).
- xnatctl.core.validation.validate_resource_label(label)[source]¶
Validate XNAT resource label (more flexible than other identifiers).
- xnatctl.core.validation.validate_ae_title(ae_title, field_name='AE Title')[source]¶
Validate DICOM Application Entity Title.
Per DICOM standard: 1-16 printable ASCII characters, no backslash.
- xnatctl.core.validation.validate_path_exists(path, *, must_be_file=False, must_be_dir=False, description='path')[source]¶
Validate that a path exists and optionally check its type.
- Parameters:
- Returns:
Resolved Path object.
- Raises:
PathValidationError – If path is invalid or doesn’t meet requirements.
- Return type:
- xnatctl.core.validation.validate_path_writable(path, description='path')[source]¶
Validate that a path is writable (parent directory exists and is writable).
- Parameters:
- Returns:
Resolved Path object.
- Raises:
PathValidationError – If path is not writable.
- Return type:
- xnatctl.core.validation.validate_archive_path(path)[source]¶
Validate that path is a supported archive file.
- Parameters:
- Returns:
Resolved Path object.
- Raises:
PathValidationError – If path is not a valid archive.
- Return type:
- xnatctl.core.validation.validate_dicom_directory(path)[source]¶
Validate that path is a directory suitable for DICOM files.
- xnatctl.core.validation.validate_timeout(value, field_name='timeout', *, min_value=1, max_value=2592000, default=21600)[source]¶
Validate timeout value in seconds.
- Parameters:
- Returns:
Validated timeout in seconds.
- Raises:
ConfigurationError – If timeout is invalid.
- Return type:
- xnatctl.core.validation.validate_workers(value, field_name='workers', *, min_value=1, max_value=100, default=4)[source]¶
Validate worker count for parallel operations.
- Parameters:
- Returns:
Validated worker count.
- Raises:
ConfigurationError – If value is invalid.
- Return type:
- xnatctl.core.validation.validate_regex_pattern(pattern, field_name='pattern')[source]¶
Validate and compile a regex pattern.
- Parameters:
- Returns:
Compiled regex pattern.
- Raises:
ConfigurationError – If pattern is invalid.
- Return type:
- xnatctl.core.validation.validate_scan_ids_input(scan_input)[source]¶
Validate and parse scan IDs input from CLI.
Accepts: - “*” for all scans (returns None) - Comma-separated list: “1,2,3,4” - Single ID: “1”
- Parameters:
scan_input (str) – Raw scan IDs input string.
- Returns:
List of scan IDs or None for all scans.
- Raises:
InvalidIdentifierError – If any scan ID is invalid.
- Return type:
- xnatctl.core.validation.validate_project_list(projects_input)[source]¶
Validate and parse comma-separated project IDs.
- Parameters:
projects_input (str) – Comma-separated project IDs.
- Returns:
List of validated project IDs.
- Raises:
InvalidIdentifierError – If any project ID is invalid.
- Return type:
Output¶
Output formatting utilities for JSON, table, and quiet modes. Uses Rich for terminal rendering.
Supported Formats:
json- Machine-readable JSON outputtable- Human-readable table with borders and alignmentquiet- Minimal output (IDs only)
Usage Example:
from xnatctl.core.output import OutputFormatter
formatter = OutputFormatter(format="table")
formatter.print_table(
data=[{"id": "proj1", "name": "Project 1"}],
columns=["id", "name"]
)
Output formatting for xnatctl.
Provides consistent output in JSON, table, and quiet modes using Rich.
- class xnatctl.core.output.OutputFormat(*values)[source]¶
Output format options.
- JSON = 'json'¶
- TABLE = 'table'¶
- xnatctl.core.output.print_table(rows, columns, *, title=None, column_labels=None)[source]¶
Print data as a Rich table.
- xnatctl.core.output.print_key_value(data, *, title=None, key_labels=None)[source]¶
Print key-value pairs in a formatted way.
- xnatctl.core.output.print_output(data, *, format=OutputFormat.TABLE, columns=None, column_labels=None, title=None, quiet=False, id_field='id')[source]¶
Print data in the specified format.
- Parameters:
data (Any) – Data to print (dict, list, or scalar).
format (OutputFormat) – Output format.
title (str | None) – Optional title.
quiet (bool) – If True, only print IDs.
id_field (str) – Field to use for IDs in quiet mode.
- xnatctl.core.output.print_error(message)[source]¶
Print error message to stderr.
The message is routed through
redact_url_query()so that URLs embedded in the error never leak secret-shaped query values.
- xnatctl.core.output.print_warning(message)[source]¶
Print warning message to stderr.
The message is routed through
redact_url_query()so that URLs embedded in the warning never leak secret-shaped query values.
Logging¶
Structured logging utilities with configurable verbosity levels.
Logging utilities for xnatctl.
Provides structured logging with audit trail support.
- xnatctl.core.logging.setup_logging(level=20, *, quiet=False, verbose=False)[source]¶
Configure logging for xnatctl.
- class xnatctl.core.logging.LogContext(operation, logger=None, **context)[source]¶
Context manager for structured logging with context fields.
- xnatctl.core.logging.log_context(operation, logger=None, **context)[source]¶
Context manager for structured logging.
- class xnatctl.core.logging.AuditLogger(logger=None)[source]¶
Logger for audit trail of operations.
- log_operation(operation, *, project=None, subject=None, session=None, user=None, success=True, details=None)[source]¶
Log an auditable operation.