[ENH]: Use datalad human-template-xfms dataset for junifer.data.get_xfm() #368

Merged
synchon merged 2 commits from update/get-xfm-src into main 2024-10-10 16:13:03 +00:00
2 changed files with 65 additions and 42 deletions

View file

@ -0,0 +1 @@
Use ``datalad``-enabled repository for template space transform files in :func:`.get_xfm` by `Synchon Mandal`_

View file

@ -6,9 +6,10 @@
from pathlib import Path from pathlib import Path
from typing import Any, Dict, Optional, Union from typing import Any, Dict, Optional, Union
import httpx import datalad.api as dl
import nibabel as nib import nibabel as nib
import numpy as np import numpy as np
from datalad.support.exceptions import IncompleteResultsError
from templateflow import api as tflow from templateflow import api as tflow
from ..utils import logger, raise_error from ..utils import logger, raise_error
@ -41,61 +42,82 @@ def get_xfm(
Raises Raises
------ ------
RuntimeError RuntimeError
If there is a problem fetching files. If there is a problem cloning the xfm dataset or
if there is a problem fetching the xfm file.
""" """
# Set default path for storage
if xfms_dir is None: if xfms_dir is None:
xfms_dir = Path().home() / "junifer" / "data" / "xfms" xfms_dir = Path().home() / "junifer" / "data" / "xfms"
logger.debug(f"Creating xfm directory at: {xfms_dir.resolve()}")
# Create default junifer data directory if not present
xfms_dir.mkdir(exist_ok=True, parents=True)
# Convert str to Path # Convert str to Path
elif not isinstance(xfms_dir, Path): if not isinstance(xfms_dir, Path):
xfms_dir = Path(xfms_dir) xfms_dir = Path(xfms_dir)
# Set local file prefix # Check if the template xfms dataset is installed at storage path
xfm_file_prefix = f"{src}_to_{dst}" is_installed = dl.Dataset(xfms_dir).is_installed()
# Set local file dir # Use existing dataset
xfm_file_dir = xfms_dir / xfm_file_prefix if is_installed:
# Create local directory if not present logger.debug(
xfm_file_dir.mkdir(exist_ok=True, parents=True) f"Found existing template xfms dataset at: {xfms_dir.resolve()}"
# Set file name with extension
xfm_file = f"{src}_to_{dst}_Composite.h5"
# Set local file path
xfm_file_path = xfm_file_dir / xfm_file
# Check if the file exists
if xfm_file_path.exists():
logger.info(
f"Found existing xfm file for {src} to {dst} at "
f"{xfm_file_path.resolve()}"
) )
return xfm_file_path # Set dataset
dataset = dl.Dataset(xfms_dir)
# Set URL # Clone a fresh copy
url = ( else:
"https://gin.g-node.org/juaml/human-template-xfms/raw/main/xfms/" logger.debug(f"Cloning template xfms dataset to: {xfms_dir.resolve()}")
f"{xfm_file_prefix}/{xfm_file}" # Clone dataset
)
# Create the file before proceeding
xfm_file_path.touch()
logger.info(f"Downloading xfm file for {src} to {dst} from {url}")
# Steam response
with httpx.stream("GET", url) as resp:
try: try:
resp.raise_for_status() dataset = dl.clone(
except httpx.HTTPError as exc: "https://github.com/juaml/human-template-xfms.git",
path=xfms_dir,
result_renderer="disabled",
)
except IncompleteResultsError as e:
raise_error( raise_error(
f"Error response {exc.response.status_code} while " msg=f"Failed to clone dataset: {e.failed}",
f"requesting {exc.request.url!r}",
klass=RuntimeError, klass=RuntimeError,
) )
else: else:
with open(xfm_file_path, "ab") as f: logger.debug(
for chunk in resp.iter_bytes(): f"Successfully cloned template xfms dataset to: "
f.write(chunk) f"{xfms_dir.resolve()}"
)
return xfm_file_path # Set file path to retrieve
xfm_file_path = (
xfms_dir / "xfms" / f"{src}_to_{dst}" / f"{src}_to_{dst}_Composite.h5"
)
# Retrieve file
try:
got = dataset.get(xfm_file_path, result_renderer="disabled")
except IncompleteResultsError as e:
raise_error(
msg=f"Failed to get file from dataset: {e.failed}",
klass=RuntimeError,
)
else:
file_path = Path(got[0]["path"])
# Conditional logging based on file fetch
status = got[0]["status"]
if status == "ok":
logger.info(
f"Successfully fetched xfm file for {src} to {dst} at "
f"{file_path.resolve()}"
)
return file_path
elif status == "notneeded":
logger.info(
f"Found existing xfm file for {src} to {dst} at "
f"{file_path.resolve()}"
)
return file_path
else:
raise_error(
f"Failed to fetch xfm file for {src} to {dst} at "
f"{file_path.resolve()}"
)
def get_template( def get_template(