Source code for xnat_ingest.api.assign_
import shutil
import traceback
from pathlib import Path
from fileformats.core import FileSet
from tqdm import tqdm
from ..helpers.logging import logger
from ..helpers.remotes import LocalSessionListing, list_session_dirs
from ..model.session import ImagingSession
[docs]
def assign(
input_dir: Path,
output_dir: Path,
project_field: str,
subject_field: str,
session_field: str,
scan_field: str | None = None,
project_id: str | None = None,
copy_mode: FileSet.CopyMode = FileSet.CopyMode.hardlink_or_copy,
unlink_source: str | None = None,
raise_errors: bool = False,
) -> list[str]:
"""Sorts the input files into sessions and stages them into the staging directory.
Parameters
----------
input_dir: Path
List of paths to search for input files. Can be local paths or S3 paths.
output_dir: Path
Path to the staging directory where the sorted sessions will be saved. This should be a local path.
project_field: str
Field name to use for extracting the project ID from the input files.
subject_field: str
Field name to use for extracting the subject ID from the input files.
session_field: str
Field name to use for extracting the session ID from the input files.
scan_field: str | None
Field name to use for extracting a description for each scan. Scans for which the field
can't be resolved are left without a description.
project_id: str | None
If provided, this project ID will be used for all sessions instead of extracting it from the input files.
Useful for instruments that upload to a single project.
copy_mode: FileSet.CopyMode
The copy mode to use when saving the sessions. This determines whether files are copied, moved or symlinked when
saving the sessions to the staging directory.
unlink_source: str | None
If "all", the grouped session directory is removed in its entirety after assignment. If "keep-metadata", the
resource data is removed but the session/scan-level metadata is left behind as a lightweight skeleton. If
None, the grouped session directory is left in place.
raise_errors: bool
If True, any errors encountered during staging will raise an exception. If False, errors will be logged and the
staging process will continue for the remaining sessions.
"""
sessions: list[LocalSessionListing] = [
LocalSessionListing(d) for d in list_session_dirs(input_dir)
]
num_sessions = len(sessions)
logger.info(
"Found %d sessions in staging directory to stage'%s'",
num_sessions,
input_dir,
)
# Ensure the output and reid directories exist
output_dir.mkdir(parents=True, exist_ok=True)
errors: list[str] = []
for session_listing in tqdm(
sessions,
total=num_sessions,
desc=f"Processing staged sessions found in '{input_dir}'",
):
try:
session = ImagingSession.load(
session_listing.cache_path,
)
session.assign(
project_field=project_field,
subject_field=subject_field,
session_field=session_field,
constant_project_id=project_id,
scan_field=scan_field,
)
session.save(
dest_dir=output_dir,
copy_mode=copy_mode,
)
except Exception as e:
if raise_errors:
raise
logger.error(
"Error assigning session '%s': %s",
session_listing.name,
str(e),
)
logger.debug(traceback.format_exc())
errors.append(str(e))
else:
if unlink_source == "all":
# remove the grouped session directory in its entirety
shutil.rmtree(session_listing.fspath)
elif unlink_source == "keep-metadata":
# remove just the resource data, leaving the session/scan-level
# metadata behind as a lightweight skeleton
session.unlink(keep_metadata=True)
return errors