[ENH]: Use datalad human-template-xfms dataset for junifer.data.get_xfm() #368
2 changed files with 65 additions and 42 deletions
1
docs/changes/newsfragments/368.enh
Normal file
1
docs/changes/newsfragments/368.enh
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Use ``datalad``-enabled repository for template space transform files in :func:`.get_xfm` by `Synchon Mandal`_
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue