From 7f4e0df4ddb9fd6cf3490171b74c9fb9d39ba7ee Mon Sep 17 00:00:00 2001 From: mathiasg Date: Wed, 31 Jul 2024 15:35:33 -0400 Subject: [PATCH 1/2] RF: Load package data with acres --- docs/requirements.txt | 1 + pyproject.toml | 1 + smriprep/__init__.py | 3 +++ smriprep/cli/run.py | 17 ++++++++------ smriprep/conftest.py | 4 ++-- smriprep/data/__init__.py | 26 ++-------------------- smriprep/interfaces/tests/data/__init__.py | 3 +++ smriprep/interfaces/tests/test_surf.py | 16 +++++-------- smriprep/utils/bids.py | 8 +++---- smriprep/utils/tests/__init__.py | 2 +- smriprep/workflows/anatomical.py | 5 +++-- smriprep/workflows/surfaces.py | 10 ++++----- smriprep/workflows/tests/test_surfaces.py | 7 +++--- 13 files changed, 43 insertions(+), 60 deletions(-) create mode 100644 smriprep/interfaces/tests/data/__init__.py diff --git a/docs/requirements.txt b/docs/requirements.txt index 32245b783f..a26c7ad188 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -11,3 +11,4 @@ sphinx_rtd_theme sphinxcontrib-apidoc ~= 0.3.0 templateflow networkx != 2.8.1 +acres diff --git a/pyproject.toml b/pyproject.toml index e8b8fbbc1f..b042c9d4b5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,6 +19,7 @@ classifiers = [ license = {file = "LICENSE"} requires-python = ">=3.10" dependencies = [ + "acres", "indexed_gzip >= 0.8.8", "lockfile", "looseversion", diff --git a/smriprep/__init__.py b/smriprep/__init__.py index 8f41228dcb..042305d305 100644 --- a/smriprep/__init__.py +++ b/smriprep/__init__.py @@ -9,6 +9,8 @@ """ +from smriprep.data import load as load_data + from .__about__ import ( __copyright__, __credits__, @@ -19,4 +21,5 @@ '__copyright__', '__credits__', '__version__', + 'load_data', ] diff --git a/smriprep/cli/run.py b/smriprep/cli/run.py index 5510bcbb65..dfd55755d0 100644 --- a/smriprep/cli/run.py +++ b/smriprep/cli/run.py @@ -51,7 +51,7 @@ def get_parser(): SpatialReferences, ) - from ..__about__ import __version__ + import smriprep parser = ArgumentParser( description='sMRIPrep: Structural MRI PREProcessing workflows', @@ -82,7 +82,11 @@ def get_parser(): ) # optional arguments - parser.add_argument('--version', action='version', version=f'smriprep v{__version__}') + parser.add_argument( + '--version', + action='version', + version=f'smriprep v{smriprep.__version__}', + ) g_bids = parser.add_argument_group('Options for filtering BIDS queries') g_bids.add_argument( @@ -470,9 +474,8 @@ def build_workflow(opts, retval): from nipype import logging from niworkflows.utils.bids import collect_participants - from ..__about__ import __version__ - from ..data import load_resource - from ..workflows.base import init_smriprep_wf + import smriprep + from smriprep.workflows.base import init_smriprep_wf logger = logging.getLogger('nipype.workflow') @@ -596,7 +599,7 @@ def build_workflow(opts, retval): logger.log( 25, INIT_MSG( - version=__version__, + version=smriprep.__version__, bids_dir=bids_dir, subject_list=subject_list, uuid=run_uuid, @@ -651,7 +654,7 @@ def build_workflow(opts, retval): boilerplate, ) - boilerplate_bib = load_resource('boilerplate.bib') + boilerplate_bib = smriprep.load_data('boilerplate.bib') # Generate HTML file resolving citations cmd = [ diff --git a/smriprep/conftest.py b/smriprep/conftest.py index ea8e2bf743..a85ba7e066 100644 --- a/smriprep/conftest.py +++ b/smriprep/conftest.py @@ -3,7 +3,7 @@ import numpy as np import pytest -from smriprep.data import load_resource +from smriprep.data import load os.environ['NO_ET'] = '1' @@ -12,5 +12,5 @@ def _populate_namespace(doctest_namespace, tmp_path): doctest_namespace['os'] = os doctest_namespace['np'] = np - doctest_namespace['load'] = load_resource + doctest_namespace['load'] = load doctest_namespace['testdir'] = tmp_path diff --git a/smriprep/data/__init__.py b/smriprep/data/__init__.py index 5cc3f3426d..9dbc26f244 100644 --- a/smriprep/data/__init__.py +++ b/smriprep/data/__init__.py @@ -1,25 +1,3 @@ -import atexit -from contextlib import ExitStack -from pathlib import Path +from acres import Loader -try: - from functools import cache -except ImportError: # PY38 - from functools import lru_cache as cache - -try: # Prefer backport to leave consistency to dependency spec - from importlib_resources import as_file, files -except ImportError: - from importlib.resources import as_file, files - -__all__ = ['load_resource'] - -exit_stack = ExitStack() -atexit.register(exit_stack.close) - -path = files(__package__) - - -@cache -def load_resource(fname: str) -> Path: - return exit_stack.enter_context(as_file(path.joinpath(fname))) +load = Loader(__package__) diff --git a/smriprep/interfaces/tests/data/__init__.py b/smriprep/interfaces/tests/data/__init__.py new file mode 100644 index 0000000000..9dbc26f244 --- /dev/null +++ b/smriprep/interfaces/tests/data/__init__.py @@ -0,0 +1,3 @@ +from acres import Loader + +load = Loader(__package__) diff --git a/smriprep/interfaces/tests/test_surf.py b/smriprep/interfaces/tests/test_surf.py index 54335d1a1e..e1fa97fd32 100644 --- a/smriprep/interfaces/tests/test_surf.py +++ b/smriprep/interfaces/tests/test_surf.py @@ -2,19 +2,15 @@ import numpy as np from nipype.pipeline import engine as pe -from ...data import load_resource +from smriprep.interfaces.tests.data import load as load_test_data + from ..surf import MakeRibbon def test_MakeRibbon(tmp_path): - res_template = '{path}/sub-fsaverage_res-4_hemi-{hemi}_desc-cropped_{surf}dist.nii.gz' + res_template = 'sub-fsaverage_res-4_hemi-{hemi}_desc-cropped_{surf}dist.nii.gz' white, pial = ( - [ - load_resource( - res_template.format(path='../interfaces/tests/data', hemi=hemi, surf=surf) - ) - for hemi in 'LR' - ] + [load_test_data(res_template.format(hemi=hemi, surf=surf)) for hemi in 'LR'] for surf in ('wm', 'pial') ) @@ -27,9 +23,7 @@ def test_MakeRibbon(tmp_path): result = make_ribbon.run() ribbon = nb.load(result.outputs.ribbon) - expected = nb.load( - load_resource('../interfaces/tests/data/sub-fsaverage_res-4_desc-cropped_ribbon.nii.gz') - ) + expected = nb.load(load_test_data('sub-fsaverage_res-4_desc-cropped_ribbon.nii.gz')) assert ribbon.shape == expected.shape assert np.allclose(ribbon.affine, expected.affine) diff --git a/smriprep/utils/bids.py b/smriprep/utils/bids.py index 958cffa33b..9871a6a22a 100644 --- a/smriprep/utils/bids.py +++ b/smriprep/utils/bids.py @@ -28,13 +28,13 @@ from bids.layout import BIDSLayout from niworkflows.data import load as nwf_load -from ..data import load_resource +import smriprep def collect_derivatives(derivatives_dir, subject_id, std_spaces, spec=None, patterns=None): """Gather existing derivatives and compose a cache.""" if spec is None or patterns is None: - _spec, _patterns = tuple(loads(load_resource('io_spec.json').read_text()).values()) + _spec, _patterns = tuple(loads(smriprep.load_data('io_spec.json').read_text()).values()) if spec is None: spec = _spec @@ -96,11 +96,11 @@ def write_derivative_description(bids_dir, deriv_dir): .. testsetup:: - >>> from smriprep.data import load_resource + >>> from smriprep.data import load >>> from pathlib import Path >>> from tempfile import TemporaryDirectory >>> tmpdir = TemporaryDirectory() - >>> bids_dir = load_resource('tests') + >>> bids_dir = load('tests') >>> deriv_desc = Path(tmpdir.name) / 'dataset_description.json' .. doctest:: diff --git a/smriprep/utils/tests/__init__.py b/smriprep/utils/tests/__init__.py index 84a88300dc..2978572d1e 100644 --- a/smriprep/utils/tests/__init__.py +++ b/smriprep/utils/tests/__init__.py @@ -1,4 +1,4 @@ -from niworkflows.data import Loader +from acres import Loader load_data = Loader(__package__) diff --git a/smriprep/workflows/anatomical.py b/smriprep/workflows/anatomical.py index 005cf047eb..974d2c57a4 100644 --- a/smriprep/workflows/anatomical.py +++ b/smriprep/workflows/anatomical.py @@ -54,7 +54,8 @@ from niworkflows.utils.misc import add_suffix from niworkflows.utils.spaces import Reference, SpatialReferences -from ..data import load_resource +import smriprep + from ..interfaces import DerivativesDataSink from ..utils.misc import apply_lut as _apply_bids_lut from ..utils.misc import fs_isRunning as _fs_isRunning @@ -1461,7 +1462,7 @@ def init_anat_template_wf( if num_files == 1: get1st = pe.Node(niu.Select(index=[0]), name='get1st') - outputnode.inputs.anat_realign_xfm = [str(load_resource('itkIdentityTransform.txt'))] + outputnode.inputs.anat_realign_xfm = [str(smriprep.load_data('itkIdentityTransform.txt'))] # fmt:off workflow.connect([ diff --git a/smriprep/workflows/surfaces.py b/smriprep/workflows/surfaces.py index c2a43b4f73..ec44155b7f 100644 --- a/smriprep/workflows/surfaces.py +++ b/smriprep/workflows/surfaces.py @@ -53,10 +53,10 @@ MetricResample, ) +import smriprep from smriprep.interfaces.surf import MakeRibbon from smriprep.interfaces.workbench import SurfaceResample -from ..data import load_resource from ..interfaces.freesurfer import MakeMidthickness, ReconAll from ..interfaces.gifti import MetricMath from ..interfaces.workbench import CreateSignedDistanceVolume @@ -723,7 +723,7 @@ def init_fsLR_reg_wf(*, name='fsLR_reg_wf'): iterfield=['sphere_in', 'sphere_project_to', 'sphere_unproject_from'], name='project_unproject', ) - atlases = load_resource('atlases') + atlases = smriprep.load_data('atlases') project_unproject.inputs.sphere_project_to = [ atlases / 'fs_L' / 'fsaverage.L.sphere.164k_fs_L.surf.gii', atlases / 'fs_R' / 'fsaverage.R.sphere.164k_fs_R.surf.gii', @@ -804,8 +804,8 @@ def init_msm_sulc_wf(*, sloppy: bool = False, name: str = 'msm_sulc_wf'): # --indata=sub-${SUB}_ses-${SES}_hemi-${HEMI)_sulc.shape.gii \ # --refdata=tpl-fsaverage_hemi-${HEMI}_den-164k_sulc.shape.gii \ # --out=${HEMI}. --verbose - atlases = load_resource('atlases') - msm_conf = load_resource(f'msm/MSMSulcStrain{"Sloppy" if sloppy else "Final"}conf') + atlases = smriprep.load_data('atlases') + msm_conf = smriprep.load_data(f'msm/MSMSulcStrain{"Sloppy" if sloppy else "Final"}conf') msmsulc = pe.MapNode( MSM(verbose=True, config_file=msm_conf), iterfield=['in_mesh', 'reference_mesh', 'in_data', 'reference_data', 'out_base'], @@ -1512,7 +1512,7 @@ def init_morph_grayords_wf( name='outputnode', ) - atlases = load_resource('atlases') + atlases = smriprep.load_data('atlases') select_surfaces = pe.Node( KeySelect( fields=[ diff --git a/smriprep/workflows/tests/test_surfaces.py b/smriprep/workflows/tests/test_surfaces.py index d768328fe7..95076da759 100644 --- a/smriprep/workflows/tests/test_surfaces.py +++ b/smriprep/workflows/tests/test_surfaces.py @@ -7,7 +7,8 @@ import pytest from nipype.pipeline import engine as pe -from ...data import load_resource +from smriprep.interfaces.tests.data import load as load_test_data + from ..surfaces import init_anat_ribbon_wf, init_gifti_surfaces_wf @@ -23,9 +24,7 @@ def test_ribbon_workflow(tmp_path: Path): # Low-res file that includes the fsaverage surfaces in its bounding box # We will use it both as a template and a comparison. - test_ribbon = load_resource( - '../interfaces/tests/data/sub-fsaverage_res-4_desc-cropped_ribbon.nii.gz' - ) + test_ribbon = load_test_data('sub-fsaverage_res-4_desc-cropped_ribbon.nii.gz') gifti_surfaces_wf = init_gifti_surfaces_wf(surfaces=['white', 'pial']) anat_ribbon_wf = init_anat_ribbon_wf() From 1acab581d75618c636861b2cf93b92c94dacbbfd Mon Sep 17 00:00:00 2001 From: Mathias Goncalves Date: Wed, 31 Jul 2024 15:36:52 -0400 Subject: [PATCH 2/2] DOC: data load module Co-authored-by: Chris Markiewicz --- smriprep/data/__init__.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/smriprep/data/__init__.py b/smriprep/data/__init__.py index 9dbc26f244..799694267b 100644 --- a/smriprep/data/__init__.py +++ b/smriprep/data/__init__.py @@ -1,3 +1,14 @@ +"""sMRIPRep data files + +.. autofunction:: load + +.. automethod:: load.readable + +.. automethod:: load.as_path + +.. automethod:: load.cached +""" + from acres import Loader load = Loader(__package__)