From 8d1354cd39d96a32c753a22a8f3aef5989147d8b Mon Sep 17 00:00:00 2001 From: Synchon Mandal Date: Tue, 12 Nov 2024 15:30:55 +0100 Subject: [PATCH 1/7] feat: introduce typing module and type hints --- junifer/__init__.pyi | 2 ++ junifer/typing/__init__.py | 9 ++++++ junifer/typing/__init__.pyi | 23 ++++++++++++++ junifer/typing/_typing.py | 61 +++++++++++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+) create mode 100644 junifer/typing/__init__.py create mode 100644 junifer/typing/__init__.pyi create mode 100644 junifer/typing/_typing.py diff --git a/junifer/__init__.pyi b/junifer/__init__.pyi index 345a6e4e4..b94805d1b 100644 --- a/junifer/__init__.pyi +++ b/junifer/__init__.pyi @@ -13,6 +13,7 @@ __all__ = [ "external", "onthefly", "testing", + "typing", "__version__", ] @@ -30,6 +31,7 @@ from . import ( utils, external, testing, + typing, onthefly, ) from ._version import __version__ diff --git a/junifer/typing/__init__.py b/junifer/typing/__init__.py new file mode 100644 index 000000000..d8bd18ce2 --- /dev/null +++ b/junifer/typing/__init__.py @@ -0,0 +1,9 @@ +"""Type hints for internal and external use.""" + +# Authors: Synchon Mandal +# License: AGPL + +import lazy_loader as lazy + + +__getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__) diff --git a/junifer/typing/__init__.pyi b/junifer/typing/__init__.pyi new file mode 100644 index 000000000..8a25d5d73 --- /dev/null +++ b/junifer/typing/__init__.pyi @@ -0,0 +1,23 @@ +__all__ = [ + "DataGrabberLike", + "PreprocessorLike", + "MarkerLike", + "StorageLike", + "PipelineComponent", + "Dependencies", + "ConditionalDependencies", + "ExternalDependencies", + "MarkerInOutMappings", +] + +from ._typing import ( + DataGrabberLike, + PreprocessorLike, + MarkerLike, + StorageLike, + PipelineComponent, + Dependencies, + ConditionalDependencies, + ExternalDependencies, + MarkerInOutMappings, +) diff --git a/junifer/typing/_typing.py b/junifer/typing/_typing.py new file mode 100644 index 000000000..c4d248e92 --- /dev/null +++ b/junifer/typing/_typing.py @@ -0,0 +1,61 @@ +"""Provide type hints for internal and external use.""" + +# Authors: Synchon Mandal +# License: AGPL + +from typing import ( + TYPE_CHECKING, + AbstractSet, + MutableMapping, + Sequence, + Type, + Union, +) + + +if TYPE_CHECKING: + from ..datagrabber import BaseDataGrabber + from ..datareader import DefaultDataReader + from ..markers import BaseMarker + from ..preprocess import BasePreprocessor + from ..storage import BaseFeatureStorage + + +__all__ = [ + "DataGrabberLike", + "PreprocessorLike", + "MarkerLike", + "StorageLike", + "PipelineComponent", + "Dependencies", + "ConditionalDependencies", + "ExternalDependencies", + "MarkerInOutMappings", +] + + +DataGrabberLike = Type["BaseDataGrabber"] +PreprocessorLike = Type["BasePreprocessor"] +MarkerLike = Type["BaseMarker"] +StorageLike = Type["BaseFeatureStorage"] +PipelineComponent = Union[ + "DataGrabberLike", + "DefaultDataReader", + "PreprocessorLike", + "MarkerLike", + "StorageLike", +] +Dependencies = AbstractSet[str] +ConditionalDependencies = Sequence[ + MutableMapping[ + str, + Union[ + str, + PipelineComponent, + Sequence[str], + Sequence[PipelineComponent], + ], + ] +] +ExternalDependencies = Sequence[MutableMapping[str, Union[str, Sequence[str]]]] +MarkerInOutMappings = MutableMapping[str, MutableMapping[str, str]] -- 2.52.0 From eccc03ff86fea36d3b5472de9d80fdfe445b7390 Mon Sep 17 00:00:00 2001 From: Synchon Mandal Date: Tue, 12 Nov 2024 15:40:07 +0100 Subject: [PATCH 2/7] style: update type hints across codebase --- junifer/api/decorators.py | 9 +++-- junifer/api/functions.py | 9 +++-- junifer/datagrabber/multiple.py | 3 +- junifer/markers/base.py | 11 ++---- junifer/markers/brainprint.py | 8 ++-- junifer/markers/complexity/complexity_base.py | 6 +-- junifer/markers/ets_rss.py | 7 ++-- junifer/markers/falff/_afni_falff.py | 6 +-- junifer/markers/falff/_junifer_falff.py | 4 +- junifer/markers/falff/falff_base.py | 8 ++-- ...ossparcellation_functional_connectivity.py | 7 ++-- .../functional_connectivity_base.py | 7 ++-- junifer/markers/parcel_aggregation.py | 7 ++-- junifer/markers/reho/_afni_reho.py | 6 +-- junifer/markers/reho/_junifer_reho.py | 4 +- junifer/markers/reho/reho_base.py | 8 ++-- junifer/markers/sphere_aggregation.py | 7 ++-- .../markers/temporal_snr/temporal_snr_base.py | 7 ++-- junifer/onthefly/_brainprint.py | 11 ++---- junifer/onthefly/read_transform.py | 9 ++--- junifer/pipeline/marker_collection.py | 18 +++------ .../pipeline/pipeline_component_registry.py | 11 ++---- .../tests/test_pipeline_step_mixin.py | 37 +++++++++---------- .../pipeline/tests/test_workdir_manager.py | 1 + .../confounds/fmriprep_confound_remover.py | 4 +- .../preprocess/smoothing/_afni_smoothing.py | 8 ++-- .../preprocess/smoothing/_fsl_smoothing.py | 9 ++--- .../smoothing/_nilearn_smoothing.py | 4 +- junifer/preprocess/smoothing/smoothing.py | 5 ++- junifer/preprocess/warping/_ants_warper.py | 8 ++-- junifer/preprocess/warping/_fsl_warper.py | 8 ++-- junifer/preprocess/warping/space_warper.py | 5 ++- .../warping/tests/test_space_warper.py | 11 ++---- 33 files changed, 122 insertions(+), 151 deletions(-) diff --git a/junifer/api/decorators.py b/junifer/api/decorators.py index 6f843164d..dd521cdb1 100644 --- a/junifer/api/decorators.py +++ b/junifer/api/decorators.py @@ -8,6 +8,7 @@ from typing import Type from ..pipeline import PipelineComponentRegistry +from ..typing import DataGrabberLike, MarkerLike, PreprocessorLike, StorageLike __all__ = [ @@ -19,7 +20,7 @@ __all__ = [ ] -def register_datagrabber(klass: Type) -> Type: +def register_datagrabber(klass: DataGrabberLike) -> DataGrabberLike: """Register DataGrabber. Registers the DataGrabber so it can be used by name. @@ -73,7 +74,7 @@ def register_datareader(klass: Type) -> Type: return klass -def register_preprocessor(klass: Type) -> Type: +def register_preprocessor(klass: PreprocessorLike) -> PreprocessorLike: """Preprocessor registration decorator. Registers the preprocessor so it can be used by name. @@ -96,7 +97,7 @@ def register_preprocessor(klass: Type) -> Type: return klass -def register_marker(klass: Type) -> Type: +def register_marker(klass: MarkerLike) -> MarkerLike: """Marker registration decorator. Registers the marker so it can be used by name. @@ -119,7 +120,7 @@ def register_marker(klass: Type) -> Type: return klass -def register_storage(klass: Type) -> Type: +def register_storage(klass: StorageLike) -> StorageLike: """Storage registration decorator. Registers the storage so it can be used by name. diff --git a/junifer/api/functions.py b/junifer/api/functions.py index 097ccf567..3ffbd3bff 100644 --- a/junifer/api/functions.py +++ b/junifer/api/functions.py @@ -20,13 +20,14 @@ from ..pipeline import ( ) from ..preprocess.base import BasePreprocessor from ..storage.base import BaseFeatureStorage +from ..typing import DataGrabberLike, MarkerLike, PreprocessorLike, StorageLike from ..utils import logger, raise_error, yaml __all__ = ["run", "collect", "queue", "reset", "list_elements"] -def _get_datagrabber(datagrabber_config: Dict) -> BaseDataGrabber: +def _get_datagrabber(datagrabber_config: Dict) -> DataGrabberLike: """Get DataGrabber. Parameters @@ -48,7 +49,7 @@ def _get_datagrabber(datagrabber_config: Dict) -> BaseDataGrabber: ) -def _get_preprocessor(preprocessing_config: Dict) -> BasePreprocessor: +def _get_preprocessor(preprocessing_config: Dict) -> PreprocessorLike: """Get Preprocessor. Parameters @@ -70,7 +71,7 @@ def _get_preprocessor(preprocessing_config: Dict) -> BasePreprocessor: ) -def _get_marker(marker_config: Dict) -> BaseMarker: +def _get_marker(marker_config: Dict) -> MarkerLike: """Get Marker. Parameters @@ -92,7 +93,7 @@ def _get_marker(marker_config: Dict) -> BaseMarker: ) -def _get_storage(storage_config: Dict) -> BaseFeatureStorage: +def _get_storage(storage_config: Dict) -> StorageLike: """Get Storage. Parameters diff --git a/junifer/datagrabber/multiple.py b/junifer/datagrabber/multiple.py index 7370dc234..83df9cfbe 100644 --- a/junifer/datagrabber/multiple.py +++ b/junifer/datagrabber/multiple.py @@ -8,6 +8,7 @@ from typing import Dict, List, Tuple, Union from ..api.decorators import register_datagrabber +from ..typing import DataGrabberLike from ..utils import deep_update, raise_error from .base import BaseDataGrabber @@ -37,7 +38,7 @@ class MultipleDataGrabber(BaseDataGrabber): """ - def __init__(self, datagrabbers: List[BaseDataGrabber], **kwargs) -> None: + def __init__(self, datagrabbers: List[DataGrabberLike], **kwargs) -> None: # Check datagrabbers consistency # Check for same element keys first_keys = datagrabbers[0].get_element_keys() diff --git a/junifer/markers/base.py b/junifer/markers/base.py index d3c60eaa3..a72e6689b 100644 --- a/junifer/markers/base.py +++ b/junifer/markers/base.py @@ -6,16 +6,13 @@ from abc import ABC, abstractmethod from copy import deepcopy -from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Optional, Union from ..pipeline import PipelineStepMixin, UpdateMetaMixin +from ..typing import StorageLike from ..utils import logger, raise_error -if TYPE_CHECKING: - from junifer.storage import BaseFeatureStorage - - __all__ = ["BaseMarker"] @@ -159,7 +156,7 @@ class BaseMarker(ABC, PipelineStepMixin, UpdateMetaMixin): type_: str, feature: str, out: Dict[str, Any], - storage: "BaseFeatureStorage", + storage: StorageLike, ) -> None: """Store. @@ -182,7 +179,7 @@ class BaseMarker(ABC, PipelineStepMixin, UpdateMetaMixin): def _fit_transform( self, input: Dict[str, Dict], - storage: Optional["BaseFeatureStorage"] = None, + storage: Optional[StorageLike] = None, ) -> Dict: """Fit and transform. diff --git a/junifer/markers/brainprint.py b/junifer/markers/brainprint.py index 13c36a1e3..72879b6b5 100644 --- a/junifer/markers/brainprint.py +++ b/junifer/markers/brainprint.py @@ -11,7 +11,6 @@ from typing import ( Dict, List, Optional, - Set, Union, ) @@ -25,6 +24,7 @@ from ..external.BrainPrint.brainprint.brainprint import ( ) from ..external.BrainPrint.brainprint.surfaces import surf_to_vtk from ..pipeline import WorkDirManager +from ..typing import Dependencies, ExternalDependencies, MarkerInOutMappings from ..utils import logger, run_ext_cmd from .base import BaseMarker @@ -68,7 +68,7 @@ class BrainPrint(BaseMarker): """ - _EXT_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, List[str]]]]] = [ + _EXT_DEPENDENCIES: ClassVar[ExternalDependencies] = [ { "name": "freesurfer", "commands": [ @@ -80,9 +80,9 @@ class BrainPrint(BaseMarker): }, ] - _DEPENDENCIES: ClassVar[Set[str]] = {"lapy", "numpy"} + _DEPENDENCIES: ClassVar[Dependencies] = {"lapy", "numpy"} - _MARKER_INOUT_MAPPINGS: ClassVar[Dict[str, Dict[str, str]]] = { + _MARKER_INOUT_MAPPINGS: ClassVar[MarkerInOutMappings] = { "FreeSurfer": { "eigenvalues": "scalar_table", "areas": "vector", diff --git a/junifer/markers/complexity/complexity_base.py b/junifer/markers/complexity/complexity_base.py index f9aa6a4f4..5e20e828d 100644 --- a/junifer/markers/complexity/complexity_base.py +++ b/junifer/markers/complexity/complexity_base.py @@ -11,10 +11,10 @@ from typing import ( Dict, List, Optional, - Set, Union, ) +from ...typing import Dependencies, MarkerInOutMappings from ...utils import raise_error from ..base import BaseMarker from ..parcel_aggregation import ParcelAggregation @@ -51,9 +51,9 @@ class ComplexityBase(BaseMarker): """ - _DEPENDENCIES: ClassVar[Set[str]] = {"nilearn", "neurokit2"} + _DEPENDENCIES: ClassVar[Dependencies] = {"nilearn", "neurokit2"} - _MARKER_INOUT_MAPPINGS: ClassVar[Dict[str, Dict[str, str]]] = { + _MARKER_INOUT_MAPPINGS: ClassVar[MarkerInOutMappings] = { "BOLD": { "complexity": "vector", }, diff --git a/junifer/markers/ets_rss.py b/junifer/markers/ets_rss.py index 31ffd70b6..0a50785a1 100644 --- a/junifer/markers/ets_rss.py +++ b/junifer/markers/ets_rss.py @@ -6,11 +6,12 @@ # Synchon Mandal # License: AGPL -from typing import Any, ClassVar, Dict, List, Optional, Set, Union +from typing import Any, ClassVar, Dict, List, Optional, Union import numpy as np from ..api.decorators import register_marker +from ..typing import Dependencies, MarkerInOutMappings from ..utils import logger from .base import BaseMarker from .parcel_aggregation import ParcelAggregation @@ -45,9 +46,9 @@ class RSSETSMarker(BaseMarker): """ - _DEPENDENCIES: ClassVar[Set[str]] = {"nilearn"} + _DEPENDENCIES: ClassVar[Dependencies] = {"nilearn"} - _MARKER_INOUT_MAPPINGS: ClassVar[Dict[str, Dict[str, str]]] = { + _MARKER_INOUT_MAPPINGS: ClassVar[MarkerInOutMappings] = { "BOLD": { "rss_ets": "timeseries", }, diff --git a/junifer/markers/falff/_afni_falff.py b/junifer/markers/falff/_afni_falff.py index c6a247187..9c3e68070 100644 --- a/junifer/markers/falff/_afni_falff.py +++ b/junifer/markers/falff/_afni_falff.py @@ -8,16 +8,14 @@ from pathlib import Path from typing import ( TYPE_CHECKING, ClassVar, - Dict, - List, Optional, Tuple, - Union, ) import nibabel as nib from ...pipeline import WorkDirManager +from ...typing import ExternalDependencies from ...utils import logger, run_ext_cmd from ...utils.singleton import Singleton @@ -37,7 +35,7 @@ class AFNIALFF(metaclass=Singleton): """ - _EXT_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, List[str]]]]] = [ + _EXT_DEPENDENCIES: ClassVar[ExternalDependencies] = [ { "name": "afni", "commands": ["3dRSFC", "3dAFNItoNIFTI"], diff --git a/junifer/markers/falff/_junifer_falff.py b/junifer/markers/falff/_junifer_falff.py index e769090ea..6afab9c90 100644 --- a/junifer/markers/falff/_junifer_falff.py +++ b/junifer/markers/falff/_junifer_falff.py @@ -9,7 +9,6 @@ from typing import ( TYPE_CHECKING, ClassVar, Optional, - Set, Tuple, ) @@ -19,6 +18,7 @@ import scipy as sp from nilearn import image as nimg from ...pipeline import WorkDirManager +from ...typing import Dependencies from ...utils import logger from ...utils.singleton import Singleton @@ -37,7 +37,7 @@ class JuniferALFF(metaclass=Singleton): """ - _DEPENDENCIES: ClassVar[Set[str]] = {"numpy", "nilearn", "scipy"} + _DEPENDENCIES: ClassVar[Dependencies] = {"numpy", "nilearn", "scipy"} def __del__(self) -> None: """Terminate the class.""" diff --git a/junifer/markers/falff/falff_base.py b/junifer/markers/falff/falff_base.py index 7095cbc5f..2bdc60efc 100644 --- a/junifer/markers/falff/falff_base.py +++ b/junifer/markers/falff/falff_base.py @@ -12,13 +12,11 @@ from typing import ( Any, ClassVar, Dict, - List, Optional, Tuple, - Type, - Union, ) +from ...typing import ConditionalDependencies, MarkerInOutMappings from ...utils.logging import logger, raise_error from ..base import BaseMarker from ._afni_falff import AFNIALFF @@ -72,7 +70,7 @@ class ALFFBase(BaseMarker): """ - _CONDITIONAL_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, Type]]]] = [ + _CONDITIONAL_DEPENDENCIES: ClassVar[ConditionalDependencies] = [ { "using": "afni", "depends_on": AFNIALFF, @@ -83,7 +81,7 @@ class ALFFBase(BaseMarker): }, ] - _MARKER_INOUT_MAPPINGS: ClassVar[Dict[str, Dict[str, str]]] = { + _MARKER_INOUT_MAPPINGS: ClassVar[MarkerInOutMappings] = { "BOLD": { "alff": "vector", "falff": "vector", diff --git a/junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py b/junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py index 0dc154fc7..8c29404b1 100644 --- a/junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py +++ b/junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py @@ -4,11 +4,12 @@ # Kaustubh R. Patil # License: AGPL -from typing import Any, ClassVar, Dict, List, Optional, Set, Union +from typing import Any, ClassVar, Dict, List, Optional, Union import pandas as pd from ...api.decorators import register_marker +from ...typing import Dependencies, MarkerInOutMappings from ...utils import logger, raise_error from ..base import BaseMarker from ..parcel_aggregation import ParcelAggregation @@ -49,9 +50,9 @@ class CrossParcellationFC(BaseMarker): """ - _DEPENDENCIES: ClassVar[Set[str]] = {"nilearn"} + _DEPENDENCIES: ClassVar[Dependencies] = {"nilearn"} - _MARKER_INOUT_MAPPINGS: ClassVar[Dict[str, Dict[str, str]]] = { + _MARKER_INOUT_MAPPINGS: ClassVar[MarkerInOutMappings] = { "BOLD": { "functional_connectivity": "matrix", }, diff --git a/junifer/markers/functional_connectivity/functional_connectivity_base.py b/junifer/markers/functional_connectivity/functional_connectivity_base.py index 3002fa47e..5c4cd19b3 100644 --- a/junifer/markers/functional_connectivity/functional_connectivity_base.py +++ b/junifer/markers/functional_connectivity/functional_connectivity_base.py @@ -5,11 +5,12 @@ from abc import abstractmethod -from typing import Any, ClassVar, Dict, List, Optional, Set, Union +from typing import Any, ClassVar, Dict, List, Optional, Union from sklearn.covariance import EmpiricalCovariance, LedoitWolf from ...external.nilearn import JuniferConnectivityMeasure +from ...typing import Dependencies, MarkerInOutMappings from ...utils import raise_error from ..base import BaseMarker @@ -51,9 +52,9 @@ class FunctionalConnectivityBase(BaseMarker): """ - _DEPENDENCIES: ClassVar[Set[str]] = {"nilearn", "scikit-learn"} + _DEPENDENCIES: ClassVar[Dependencies] = {"nilearn", "scikit-learn"} - _MARKER_INOUT_MAPPINGS: ClassVar[Dict[str, Dict[str, str]]] = { + _MARKER_INOUT_MAPPINGS: ClassVar[MarkerInOutMappings] = { "BOLD": { "functional_connectivity": "matrix", }, diff --git a/junifer/markers/parcel_aggregation.py b/junifer/markers/parcel_aggregation.py index e090516af..92a122d42 100644 --- a/junifer/markers/parcel_aggregation.py +++ b/junifer/markers/parcel_aggregation.py @@ -4,7 +4,7 @@ # Synchon Mandal # License: AGPL -from typing import Any, ClassVar, Dict, List, Optional, Set, Union +from typing import Any, ClassVar, Dict, List, Optional, Union import numpy as np from nilearn.image import math_img @@ -13,6 +13,7 @@ from nilearn.maskers import NiftiMasker from ..api.decorators import register_marker from ..data import get_data from ..stats import get_aggfunc_by_name +from ..typing import Dependencies, MarkerInOutMappings from ..utils import logger, raise_error, warn_with_log from .base import BaseMarker @@ -61,9 +62,9 @@ class ParcelAggregation(BaseMarker): """ - _DEPENDENCIES: ClassVar[Set[str]] = {"nilearn", "numpy"} + _DEPENDENCIES: ClassVar[Dependencies] = {"nilearn", "numpy"} - _MARKER_INOUT_MAPPINGS: ClassVar[Dict[str, Dict[str, str]]] = { + _MARKER_INOUT_MAPPINGS: ClassVar[MarkerInOutMappings] = { "T1w": { "aggregation": "vector", }, diff --git a/junifer/markers/reho/_afni_reho.py b/junifer/markers/reho/_afni_reho.py index 8b386a912..d681e0fc6 100644 --- a/junifer/markers/reho/_afni_reho.py +++ b/junifer/markers/reho/_afni_reho.py @@ -8,16 +8,14 @@ from pathlib import Path from typing import ( TYPE_CHECKING, ClassVar, - Dict, - List, Optional, Tuple, - Union, ) import nibabel as nib from ...pipeline import WorkDirManager +from ...typing import ExternalDependencies from ...utils import logger, run_ext_cmd from ...utils.singleton import Singleton @@ -37,7 +35,7 @@ class AFNIReHo(metaclass=Singleton): """ - _EXT_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, List[str]]]]] = [ + _EXT_DEPENDENCIES: ClassVar[ExternalDependencies] = [ { "name": "afni", "commands": ["3dReHo", "3dAFNItoNIFTI"], diff --git a/junifer/markers/reho/_junifer_reho.py b/junifer/markers/reho/_junifer_reho.py index 27cfff566..a82ddd662 100644 --- a/junifer/markers/reho/_junifer_reho.py +++ b/junifer/markers/reho/_junifer_reho.py @@ -9,7 +9,6 @@ from pathlib import Path from typing import ( TYPE_CHECKING, ClassVar, - Set, Tuple, ) @@ -20,6 +19,7 @@ from nilearn import image as nimg from nilearn import masking as nmask from ...pipeline import WorkDirManager +from ...typing import Dependencies from ...utils import logger, raise_error from ...utils.singleton import Singleton @@ -38,7 +38,7 @@ class JuniferReHo(metaclass=Singleton): """ - _DEPENDENCIES: ClassVar[Set[str]] = {"numpy", "nilearn", "scipy"} + _DEPENDENCIES: ClassVar[Dependencies] = {"numpy", "nilearn", "scipy"} def __del__(self) -> None: """Terminate the class.""" diff --git a/junifer/markers/reho/reho_base.py b/junifer/markers/reho/reho_base.py index 8d5d7d6f5..6fcdcc403 100644 --- a/junifer/markers/reho/reho_base.py +++ b/junifer/markers/reho/reho_base.py @@ -10,13 +10,11 @@ from typing import ( Any, ClassVar, Dict, - List, Optional, Tuple, - Type, - Union, ) +from ...typing import ConditionalDependencies, MarkerInOutMappings from ...utils import logger, raise_error from ..base import BaseMarker from ._afni_reho import AFNIReHo @@ -51,7 +49,7 @@ class ReHoBase(BaseMarker): """ - _CONDITIONAL_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, Type]]]] = [ + _CONDITIONAL_DEPENDENCIES: ClassVar[ConditionalDependencies] = [ { "using": "afni", "depends_on": AFNIReHo, @@ -62,7 +60,7 @@ class ReHoBase(BaseMarker): }, ] - _MARKER_INOUT_MAPPINGS: ClassVar[Dict[str, Dict[str, str]]] = { + _MARKER_INOUT_MAPPINGS: ClassVar[MarkerInOutMappings] = { "BOLD": { "reho": "vector", }, diff --git a/junifer/markers/sphere_aggregation.py b/junifer/markers/sphere_aggregation.py index d8a526171..a6518155b 100644 --- a/junifer/markers/sphere_aggregation.py +++ b/junifer/markers/sphere_aggregation.py @@ -4,12 +4,13 @@ # Synchon Mandal # License: AGPL -from typing import Any, ClassVar, Dict, List, Optional, Set, Union +from typing import Any, ClassVar, Dict, List, Optional, Union from ..api.decorators import register_marker from ..data import get_data from ..external.nilearn import JuniferNiftiSpheresMasker from ..stats import get_aggfunc_by_name +from ..typing import Dependencies, MarkerInOutMappings from ..utils import logger, raise_error, warn_with_log from .base import BaseMarker @@ -66,9 +67,9 @@ class SphereAggregation(BaseMarker): """ - _DEPENDENCIES: ClassVar[Set[str]] = {"nilearn", "numpy"} + _DEPENDENCIES: ClassVar[Dependencies] = {"nilearn", "numpy"} - _MARKER_INOUT_MAPPINGS: ClassVar[Dict[str, Dict[str, str]]] = { + _MARKER_INOUT_MAPPINGS: ClassVar[MarkerInOutMappings] = { "T1w": { "aggregation": "vector", }, diff --git a/junifer/markers/temporal_snr/temporal_snr_base.py b/junifer/markers/temporal_snr/temporal_snr_base.py index 76c83e339..4a11eacb5 100644 --- a/junifer/markers/temporal_snr/temporal_snr_base.py +++ b/junifer/markers/temporal_snr/temporal_snr_base.py @@ -5,10 +5,11 @@ from abc import abstractmethod -from typing import Any, ClassVar, Dict, List, Optional, Set, Union +from typing import Any, ClassVar, Dict, List, Optional, Union from nilearn import image as nimg +from ...typing import Dependencies, MarkerInOutMappings from ...utils import raise_error from ..base import BaseMarker @@ -37,9 +38,9 @@ class TemporalSNRBase(BaseMarker): """ - _DEPENDENCIES: ClassVar[Set[str]] = {"nilearn"} + _DEPENDENCIES: ClassVar[Dependencies] = {"nilearn"} - _MARKER_INOUT_MAPPINGS: ClassVar[Dict[str, Dict[str, str]]] = { + _MARKER_INOUT_MAPPINGS: ClassVar[MarkerInOutMappings] = { "BOLD": { "tsnr": "vector", }, diff --git a/junifer/onthefly/_brainprint.py b/junifer/onthefly/_brainprint.py index df4355d74..74af49f02 100644 --- a/junifer/onthefly/_brainprint.py +++ b/junifer/onthefly/_brainprint.py @@ -3,23 +3,20 @@ # Authors: Synchon Mandal # License: AGPL -from typing import TYPE_CHECKING, Dict, Optional, Type +from typing import Dict, Optional import numpy as np import pandas as pd +from ..typing import StorageLike from ..utils import raise_error -if TYPE_CHECKING: - from junifer.storage import BaseFeatureStorage - - __all__ = ["normalize", "reweight"] def normalize( - storage: Type["BaseFeatureStorage"], + storage: StorageLike, features: Dict[str, Dict[str, Optional[str]]], kind: str, ) -> pd.DataFrame: @@ -89,7 +86,7 @@ def normalize( def reweight( - storage: Type["BaseFeatureStorage"], + storage: StorageLike, feature_name: Optional[str] = None, feature_md5: Optional[str] = None, ) -> pd.DataFrame: diff --git a/junifer/onthefly/read_transform.py b/junifer/onthefly/read_transform.py index 3cc656f13..8b7cdd3d6 100644 --- a/junifer/onthefly/read_transform.py +++ b/junifer/onthefly/read_transform.py @@ -4,22 +4,19 @@ # License: AGPL -from typing import TYPE_CHECKING, Dict, Optional, Tuple, Type +from typing import Dict, Optional, Tuple import pandas as pd +from ..typing import StorageLike from ..utils import logger, raise_error, warn_with_log -if TYPE_CHECKING: - from junifer.storage import BaseFeatureStorage - - __all__ = ["read_transform"] def read_transform( - storage: Type["BaseFeatureStorage"], + storage: StorageLike, transform: str, feature_name: Optional[str] = None, feature_md5: Optional[str] = None, diff --git a/junifer/pipeline/marker_collection.py b/junifer/pipeline/marker_collection.py index ba8e492ad..b83255ca6 100644 --- a/junifer/pipeline/marker_collection.py +++ b/junifer/pipeline/marker_collection.py @@ -5,20 +5,14 @@ # License: AGPL from collections import Counter -from typing import TYPE_CHECKING, Dict, List, Optional +from typing import Dict, List, Optional from ..datareader import DefaultDataReader from ..pipeline import PipelineStepMixin, WorkDirManager +from ..typing import DataGrabberLike, MarkerLike, PreprocessorLike, StorageLike from ..utils import logger, raise_error -if TYPE_CHECKING: - from junifer.datagrabber import BaseDataGrabber - from junifer.markers import BaseMarker - from junifer.preprocess import BasePreprocessor - from junifer.storage import BaseFeatureStorage - - __all__ = ["MarkerCollection"] @@ -45,10 +39,10 @@ class MarkerCollection: def __init__( self, - markers: List["BaseMarker"], + markers: List[MarkerLike], datareader: Optional[PipelineStepMixin] = None, - preprocessors: Optional[List["BasePreprocessor"]] = None, - storage: Optional["BaseFeatureStorage"] = None, + preprocessors: Optional[List[PreprocessorLike]] = None, + storage: Optional[StorageLike] = None, ): # Check that the markers have different names marker_names = [m.name for m in markers] @@ -111,7 +105,7 @@ class MarkerCollection: return None if self._storage else out - def validate(self, datagrabber: "BaseDataGrabber") -> None: + def validate(self, datagrabber: DataGrabberLike) -> None: """Validate the pipeline. Without doing any computation, check if the marker collection can diff --git a/junifer/pipeline/pipeline_component_registry.py b/junifer/pipeline/pipeline_component_registry.py index 76f2d118e..fb5ee74c6 100644 --- a/junifer/pipeline/pipeline_component_registry.py +++ b/junifer/pipeline/pipeline_component_registry.py @@ -6,18 +6,13 @@ # License: AGPL import importlib -from typing import TYPE_CHECKING, Dict, List, Mapping, Optional, Union +from typing import Dict, List, Mapping, Optional, Union +from ..typing import DataGrabberLike, MarkerLike, PreprocessorLike, StorageLike from ..utils import logger, raise_error from ..utils.singleton import Singleton -if TYPE_CHECKING: - from ..datagrabber import BaseDataGrabber - from ..storage import BaseFeatureStorage - from .pipeline_step_mixin import PipelineStepMixin - - __all__ = ["PipelineComponentRegistry"] @@ -241,7 +236,7 @@ class PipelineComponentRegistry(metaclass=Singleton): name: str, baseclass: type, init_params: Optional[Dict] = None, - ) -> Union["BaseDataGrabber", "PipelineStepMixin", "BaseFeatureStorage"]: + ) -> Union[DataGrabberLike, PreprocessorLike, MarkerLike, StorageLike]: """Build an instance of class registered as ``name``. Parameters diff --git a/junifer/pipeline/tests/test_pipeline_step_mixin.py b/junifer/pipeline/tests/test_pipeline_step_mixin.py index 659675ebc..22f5eff9f 100644 --- a/junifer/pipeline/tests/test_pipeline_step_mixin.py +++ b/junifer/pipeline/tests/test_pipeline_step_mixin.py @@ -5,12 +5,17 @@ # License: AGPL import warnings -from typing import ClassVar, Dict, List, Set, Type, Union +from typing import ClassVar, Dict, List import pytest from junifer.pipeline.pipeline_step_mixin import PipelineStepMixin from junifer.pipeline.utils import _check_afni +from junifer.typing import ( + ConditionalDependencies, + Dependencies, + ExternalDependencies, +) def test_PipelineStepMixin_correct_dependencies() -> None: @@ -19,7 +24,7 @@ def test_PipelineStepMixin_correct_dependencies() -> None: class CorrectMixer(PipelineStepMixin): """Test class for validation.""" - _DEPENDENCIES: ClassVar[Set[str]] = {"math"} + _DEPENDENCIES: ClassVar[Dependencies] = {"math"} def validate_input(self, input: List[str]) -> List[str]: return input @@ -40,7 +45,7 @@ def test_PipelineStepMixin_incorrect_dependencies() -> None: class IncorrectMixer(PipelineStepMixin): """Test class for validation.""" - _DEPENDENCIES: ClassVar[Set[str]] = {"foobar"} + _DEPENDENCIES: ClassVar[Dependencies] = {"foobar"} def validate_input(self, input: List[str]) -> List[str]: return input @@ -65,7 +70,7 @@ def test_PipelineStepMixin_correct_ext_dependencies() -> None: class CorrectMixer(PipelineStepMixin): """Test class for validation.""" - _EXT_DEPENDENCIES: ClassVar[List[Dict[str, str]]] = [{"name": "afni"}] + _EXT_DEPENDENCIES: ClassVar[ExternalDependencies] = [{"name": "afni"}] def validate_input(self, input: List[str]) -> List[str]: return input @@ -89,7 +94,7 @@ def test_PipelineStepMixin_ext_deps_correct_commands() -> None: class CorrectMixer(PipelineStepMixin): """Test class for validation.""" - _EXT_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, List[str]]]]] = [ + _EXT_DEPENDENCIES: ClassVar[ExternalDependencies] = [ {"name": "afni", "commands": ["3dReHo"]} ] @@ -117,7 +122,7 @@ def test_PipelineStepMixin_ext_deps_incorrect_commands() -> None: class CorrectMixer(PipelineStepMixin): """Test class for validation.""" - _EXT_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, List[str]]]]] = [ + _EXT_DEPENDENCIES: ClassVar[ExternalDependencies] = [ {"name": "afni", "commands": ["3d"]} ] @@ -141,7 +146,7 @@ def test_PipelineStepMixin_incorrect_ext_dependencies() -> None: class IncorrectMixer(PipelineStepMixin): """Test class for validation.""" - _EXT_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, bool]]]] = [ + _EXT_DEPENDENCIES: ClassVar[ExternalDependencies] = [ {"name": "foobar", "optional": True} ] @@ -163,14 +168,12 @@ def test_PipelineStepMixin_correct_conditional_dependencies() -> None: """Test fit-transform with correct conditional dependencies.""" class Dependency: - _DEPENDENCIES: ClassVar[Set[str]] = {"math"} + _DEPENDENCIES: ClassVar[Dependencies] = {"math"} class CorrectMixer(PipelineStepMixin): """Test class for validation.""" - _CONDITIONAL_DEPENDENCIES: ClassVar[ - List[Dict[str, Union[str, Type]]] - ] = [ + _CONDITIONAL_DEPENDENCIES: ClassVar[ConditionalDependencies] = [ { "using": "math", "depends_on": Dependency, @@ -196,14 +199,12 @@ def test_PipelineStepMixin_incorrect_conditional_dependencies() -> None: """Test fit-transform with incorrect conditional dependencies.""" class Dependency: - _DEPENDENCIES: ClassVar[Set[str]] = {"math"} + _DEPENDENCIES: ClassVar[Dependencies] = {"math"} class IncorrectMixer(PipelineStepMixin): """Test class for validation.""" - _CONDITIONAL_DEPENDENCIES: ClassVar[ - List[Dict[str, Union[str, Type]]] - ] = [ + _CONDITIONAL_DEPENDENCIES: ClassVar[ConditionalDependencies] = [ { "using": "math", "depends_on": Dependency, @@ -231,14 +232,12 @@ def test_PipelineStepMixin_correct_conditional_ext_dependencies() -> None: """Test fit-transform with correct conditional external dependencies.""" class ExternalDependency: - _EXT_DEPENDENCIES: ClassVar[List[Dict[str, str]]] = [{"name": "afni"}] + _EXT_DEPENDENCIES: ClassVar[ExternalDependencies] = [{"name": "afni"}] class CorrectMixer(PipelineStepMixin): """Test class for validation.""" - _CONDITIONAL_DEPENDENCIES: ClassVar[ - List[Dict[str, Union[str, Type]]] - ] = [ + _CONDITIONAL_DEPENDENCIES: ClassVar[ConditionalDependencies] = [ { "using": "afni", "depends_on": ExternalDependency, diff --git a/junifer/pipeline/tests/test_workdir_manager.py b/junifer/pipeline/tests/test_workdir_manager.py index cbe423dbe..983112bee 100644 --- a/junifer/pipeline/tests/test_workdir_manager.py +++ b/junifer/pipeline/tests/test_workdir_manager.py @@ -103,6 +103,7 @@ def test_workdir_manager_get_and_delete_tempdir(tmp_path: Path) -> None: # Should remove temporary directory assert workdir_mgr.root_tempdir is None + def test_workdir_manager_no_cleanup(tmp_path: Path) -> None: """Test WorkDirManager correctly bypasses cleanup. diff --git a/junifer/preprocess/confounds/fmriprep_confound_remover.py b/junifer/preprocess/confounds/fmriprep_confound_remover.py index f296ea18f..11b5de601 100644 --- a/junifer/preprocess/confounds/fmriprep_confound_remover.py +++ b/junifer/preprocess/confounds/fmriprep_confound_remover.py @@ -11,7 +11,6 @@ from typing import ( Dict, List, Optional, - Set, Tuple, Union, ) @@ -23,6 +22,7 @@ from nilearn._utils.niimg_conversions import check_niimg_4d from ...api.decorators import register_preprocessor from ...data import get_data +from ...typing import Dependencies from ...utils import logger, raise_error from ..base import BasePreprocessor @@ -152,7 +152,7 @@ class fMRIPrepConfoundRemover(BasePreprocessor): """ - _DEPENDENCIES: ClassVar[Set[str]] = {"numpy", "nilearn"} + _DEPENDENCIES: ClassVar[Dependencies] = {"numpy", "nilearn"} def __init__( self, diff --git a/junifer/preprocess/smoothing/_afni_smoothing.py b/junifer/preprocess/smoothing/_afni_smoothing.py index 9393859e6..80f7da691 100644 --- a/junifer/preprocess/smoothing/_afni_smoothing.py +++ b/junifer/preprocess/smoothing/_afni_smoothing.py @@ -6,15 +6,13 @@ from typing import ( TYPE_CHECKING, ClassVar, - Dict, - List, - Set, Union, ) import nibabel as nib from ...pipeline import WorkDirManager +from ...typing import Dependencies, ExternalDependencies from ...utils import logger, run_ext_cmd @@ -32,14 +30,14 @@ class AFNISmoothing: """ - _EXT_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, List[str]]]]] = [ + _EXT_DEPENDENCIES: ClassVar[ExternalDependencies] = [ { "name": "afni", "commands": ["3dBlurToFWHM"], }, ] - _DEPENDENCIES: ClassVar[Set[str]] = {"nibabel"} + _DEPENDENCIES: ClassVar[Dependencies] = {"nibabel"} def preprocess( self, diff --git a/junifer/preprocess/smoothing/_fsl_smoothing.py b/junifer/preprocess/smoothing/_fsl_smoothing.py index 2e02ea222..65d67c098 100644 --- a/junifer/preprocess/smoothing/_fsl_smoothing.py +++ b/junifer/preprocess/smoothing/_fsl_smoothing.py @@ -6,15 +6,12 @@ from typing import ( TYPE_CHECKING, ClassVar, - Dict, - List, - Set, - Union, ) import nibabel as nib from ...pipeline import WorkDirManager +from ...typing import Dependencies, ExternalDependencies from ...utils import logger, run_ext_cmd @@ -32,14 +29,14 @@ class FSLSmoothing: """ - _EXT_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, List[str]]]]] = [ + _EXT_DEPENDENCIES: ClassVar[ExternalDependencies] = [ { "name": "fsl", "commands": ["susan"], }, ] - _DEPENDENCIES: ClassVar[Set[str]] = {"nibabel"} + _DEPENDENCIES: ClassVar[Dependencies] = {"nibabel"} def preprocess( self, diff --git a/junifer/preprocess/smoothing/_nilearn_smoothing.py b/junifer/preprocess/smoothing/_nilearn_smoothing.py index 1ef0498ee..bfba8f3f3 100644 --- a/junifer/preprocess/smoothing/_nilearn_smoothing.py +++ b/junifer/preprocess/smoothing/_nilearn_smoothing.py @@ -7,13 +7,13 @@ from typing import ( TYPE_CHECKING, ClassVar, Literal, - Set, Union, ) from nilearn import image as nimg from numpy.typing import ArrayLike +from ...typing import Dependencies from ...utils import logger @@ -31,7 +31,7 @@ class NilearnSmoothing: """ - _DEPENDENCIES: ClassVar[Set[str]] = {"nilearn"} + _DEPENDENCIES: ClassVar[Dependencies] = {"nilearn"} def preprocess( self, diff --git a/junifer/preprocess/smoothing/smoothing.py b/junifer/preprocess/smoothing/smoothing.py index 16f71a394..93191c94e 100644 --- a/junifer/preprocess/smoothing/smoothing.py +++ b/junifer/preprocess/smoothing/smoothing.py @@ -3,9 +3,10 @@ # Authors: Synchon Mandal # License: AGPL -from typing import Any, ClassVar, Dict, List, Optional, Tuple, Type, Union +from typing import Any, ClassVar, Dict, List, Optional, Tuple, Union from ...api.decorators import register_preprocessor +from ...typing import ConditionalDependencies from ...utils import logger, raise_error from ..base import BasePreprocessor from ._afni_smoothing import AFNISmoothing @@ -67,7 +68,7 @@ class Smoothing(BasePreprocessor): """ - _CONDITIONAL_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, Type]]]] = [ + _CONDITIONAL_DEPENDENCIES: ClassVar[ConditionalDependencies] = [ { "using": "nilearn", "depends_on": NilearnSmoothing, diff --git a/junifer/preprocess/warping/_ants_warper.py b/junifer/preprocess/warping/_ants_warper.py index eea08f428..dfc4e7bf8 100644 --- a/junifer/preprocess/warping/_ants_warper.py +++ b/junifer/preprocess/warping/_ants_warper.py @@ -7,9 +7,6 @@ from typing import ( Any, ClassVar, Dict, - List, - Set, - Union, ) import nibabel as nib @@ -17,6 +14,7 @@ import numpy as np from ...data import get_template, get_xfm from ...pipeline import WorkDirManager +from ...typing import Dependencies, ExternalDependencies from ...utils import logger, run_ext_cmd @@ -31,14 +29,14 @@ class ANTsWarper: """ - _EXT_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, List[str]]]]] = [ + _EXT_DEPENDENCIES: ClassVar[ExternalDependencies] = [ { "name": "ants", "commands": ["ResampleImage", "antsApplyTransforms"], }, ] - _DEPENDENCIES: ClassVar[Set[str]] = {"numpy", "nibabel"} + _DEPENDENCIES: ClassVar[Dependencies] = {"numpy", "nibabel"} def preprocess( self, diff --git a/junifer/preprocess/warping/_fsl_warper.py b/junifer/preprocess/warping/_fsl_warper.py index 3c32de64c..c04ae6582 100644 --- a/junifer/preprocess/warping/_fsl_warper.py +++ b/junifer/preprocess/warping/_fsl_warper.py @@ -7,15 +7,13 @@ from typing import ( Any, ClassVar, Dict, - List, - Set, - Union, ) import nibabel as nib import numpy as np from ...pipeline import WorkDirManager +from ...typing import Dependencies, ExternalDependencies from ...utils import logger, run_ext_cmd @@ -30,14 +28,14 @@ class FSLWarper: """ - _EXT_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, List[str]]]]] = [ + _EXT_DEPENDENCIES: ClassVar[ExternalDependencies] = [ { "name": "fsl", "commands": ["flirt", "applywarp"], }, ] - _DEPENDENCIES: ClassVar[Set[str]] = {"numpy", "nibabel"} + _DEPENDENCIES: ClassVar[Dependencies] = {"numpy", "nibabel"} def preprocess( self, diff --git a/junifer/preprocess/warping/space_warper.py b/junifer/preprocess/warping/space_warper.py index cdfccf1d0..445bc4c5c 100644 --- a/junifer/preprocess/warping/space_warper.py +++ b/junifer/preprocess/warping/space_warper.py @@ -3,11 +3,12 @@ # Authors: Synchon Mandal # License: AGPL -from typing import Any, ClassVar, Dict, List, Optional, Tuple, Type, Union +from typing import Any, ClassVar, Dict, List, Optional, Tuple, Union from templateflow import api as tflow from ...api.decorators import register_preprocessor +from ...typing import ConditionalDependencies from ...utils import logger, raise_error from ..base import BasePreprocessor from ._ants_warper import ANTsWarper @@ -46,7 +47,7 @@ class SpaceWarper(BasePreprocessor): """ - _CONDITIONAL_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, Type]]]] = [ + _CONDITIONAL_DEPENDENCIES: ClassVar[ConditionalDependencies] = [ { "using": "fsl", "depends_on": FSLWarper, diff --git a/junifer/preprocess/warping/tests/test_space_warper.py b/junifer/preprocess/warping/tests/test_space_warper.py index cb1299ade..858365a5d 100644 --- a/junifer/preprocess/warping/tests/test_space_warper.py +++ b/junifer/preprocess/warping/tests/test_space_warper.py @@ -4,7 +4,7 @@ # License: AGPL import socket -from typing import TYPE_CHECKING, Tuple, Type +from typing import Tuple, Type import pytest from numpy.testing import assert_array_equal, assert_raises @@ -14,10 +14,7 @@ from junifer.datareader import DefaultDataReader from junifer.pipeline.utils import _check_ants, _check_fsl from junifer.preprocess import SpaceWarper from junifer.testing.datagrabbers import PartlyCloudyTestingDataGrabber - - -if TYPE_CHECKING: - from junifer.datagrabber import BaseDataGrabber +from junifer.typing import DataGrabberLike @pytest.mark.parametrize( @@ -99,7 +96,7 @@ def test_SpaceWarper_errors( reason="only for juseless", ) def test_SpaceWarper_native( - datagrabber: "BaseDataGrabber", element: Tuple[str, ...], using: str + datagrabber: DataGrabberLike, element: Tuple[str, ...], using: str ) -> None: """Test SpaceWarper for native space warping. @@ -162,7 +159,7 @@ def test_SpaceWarper_native( _check_ants() is False, reason="requires ANTs to be in PATH" ) def test_SpaceWarper_multi_mni( - datagrabber: "BaseDataGrabber", + datagrabber: DataGrabberLike, element: Tuple[str, ...], space: str, ) -> None: -- 2.52.0 From fd209063a6f77dd23f9bb3b6c107cb761e26832b Mon Sep 17 00:00:00 2001 From: Synchon Mandal Date: Tue, 12 Nov 2024 15:41:58 +0100 Subject: [PATCH 3/7] docs: update type hints --- docs/extending/dependencies.rst | 10 +++++----- docs/extending/marker.rst | 5 +++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/extending/dependencies.rst b/docs/extending/dependencies.rst index d1b538853..441ba5414 100644 --- a/docs/extending/dependencies.rst +++ b/docs/extending/dependencies.rst @@ -28,7 +28,7 @@ component depends on. For example, for :class:`.RSSETSMarker`, we have: .. code-block:: python - _DEPENDENCIES: ClassVar[Set[str]] = {"nilearn"} + _DEPENDENCIES: ClassVar[Dependencies] = {"nilearn"} The type annotation is for documentation and static type checking purposes. Although not required, we highly recommend you use them, your future self @@ -44,7 +44,7 @@ by having a class attribute like so: .. code-block:: python - _EXT_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, List[str]]]]] = [ + _EXT_DEPENDENCIES: ClassVar[ExternalDependencies] = [ { "name": "afni", "commands": ["3dReHo", "3dAFNItoNIFTI"], @@ -78,7 +78,7 @@ that it shows the problem a bit better and how we solve it: class SpaceWarper(BasePreprocessor): # docstring - _CONDITIONAL_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, Type]]]] = [ + _CONDITIONAL_DEPENDENCIES: ClassVar[ConditionalDependencies] = [ { "using": "fsl", "depends_on": FSLWarper, @@ -115,14 +115,14 @@ similar. ``FSLWarper`` looks like this (only the relevant part is shown here): class FSLWarper: # docstring - _EXT_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, List[str]]]]] = [ + _EXT_DEPENDENCIES: ClassVar[ExternalDependencies] = [ { "name": "fsl", "commands": ["flirt", "applywarp"], }, ] - _DEPENDENCIES: ClassVar[Set[str]] = {"numpy", "nibabel"} + _DEPENDENCIES: ClassVar[Dependencies] = {"numpy", "nibabel"} def preprocess( self, diff --git a/docs/extending/marker.rst b/docs/extending/marker.rst index e2cc3faad..d73c6e821 100644 --- a/docs/extending/marker.rst +++ b/docs/extending/marker.rst @@ -196,15 +196,16 @@ Finally, we need to register the Marker using the ``@register_marker`` decorator from junifer.api.decorators import register_marker from junifer.data import get_parcellation from junifer.markers import BaseMarker + from junifer.typing import Dependencies, MarkerInOutMappings from nilearn.maskers import NiftiLabelsMasker @register_marker class ParcelMean(BaseMarker): - _DEPENDENCIES = {"nilearn", "numpy"} + _DEPENDENCIES: ClassVar[Dependencies] = {"nilearn", "numpy"} - _MARKER_INOUT_MAPPINGS: ClassVar[dict[str, dict[str, str]]] = { + _MARKER_INOUT_MAPPINGS: ClassVar[MarkerInOutMappings] = { "BOLD": { "parcel_mean": "timeseries", }, -- 2.52.0 From 86b343679035326f41e6f6cdc54112bcf0cf21ef Mon Sep 17 00:00:00 2001 From: Synchon Mandal Date: Tue, 12 Nov 2024 15:42:29 +0100 Subject: [PATCH 4/7] chore: improve imports in api.functions --- junifer/api/functions.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/junifer/api/functions.py b/junifer/api/functions.py index 3ffbd3bff..87ee4dc99 100644 --- a/junifer/api/functions.py +++ b/junifer/api/functions.py @@ -11,15 +11,15 @@ from pathlib import Path from typing import Dict, List, Optional, Tuple, Union from ..api.queue_context import GnuParallelLocalAdapter, HTCondorAdapter -from ..datagrabber.base import BaseDataGrabber -from ..markers.base import BaseMarker +from ..datagrabber import BaseDataGrabber +from ..markers import BaseMarker from ..pipeline import ( MarkerCollection, PipelineComponentRegistry, WorkDirManager, ) -from ..preprocess.base import BasePreprocessor -from ..storage.base import BaseFeatureStorage +from ..preprocess import BasePreprocessor +from ..storage import BaseFeatureStorage from ..typing import DataGrabberLike, MarkerLike, PreprocessorLike, StorageLike from ..utils import logger, raise_error, yaml -- 2.52.0 From a796251b7c972c793578ebae2e6405f963514464 Mon Sep 17 00:00:00 2001 From: Synchon Mandal Date: Tue, 12 Nov 2024 15:43:02 +0100 Subject: [PATCH 5/7] chore: update imports for Nifti1Image --- junifer/markers/falff/_afni_falff.py | 2 +- junifer/markers/falff/_junifer_falff.py | 2 +- junifer/markers/falff/falff_base.py | 2 +- junifer/markers/reho/_afni_reho.py | 2 +- junifer/markers/reho/_junifer_reho.py | 2 +- junifer/markers/reho/reho_base.py | 2 +- junifer/preprocess/smoothing/_afni_smoothing.py | 2 +- junifer/preprocess/smoothing/_fsl_smoothing.py | 2 +- junifer/preprocess/smoothing/_nilearn_smoothing.py | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/junifer/markers/falff/_afni_falff.py b/junifer/markers/falff/_afni_falff.py index 9c3e68070..211deac4b 100644 --- a/junifer/markers/falff/_afni_falff.py +++ b/junifer/markers/falff/_afni_falff.py @@ -21,7 +21,7 @@ from ...utils.singleton import Singleton if TYPE_CHECKING: - from nibabel import Nifti1Image + from nibabel.nifti1 import Nifti1Image __all__ = ["AFNIALFF"] diff --git a/junifer/markers/falff/_junifer_falff.py b/junifer/markers/falff/_junifer_falff.py index 6afab9c90..46c0f033a 100644 --- a/junifer/markers/falff/_junifer_falff.py +++ b/junifer/markers/falff/_junifer_falff.py @@ -24,7 +24,7 @@ from ...utils.singleton import Singleton if TYPE_CHECKING: - from nibabel import Nifti1Image + from nibabel.nifti1 import Nifti1Image __all__ = ["JuniferALFF"] diff --git a/junifer/markers/falff/falff_base.py b/junifer/markers/falff/falff_base.py index 2bdc60efc..4efdea850 100644 --- a/junifer/markers/falff/falff_base.py +++ b/junifer/markers/falff/falff_base.py @@ -24,7 +24,7 @@ from ._junifer_falff import JuniferALFF if TYPE_CHECKING: - from nibabel import Nifti1Image + from nibabel.nifti1 import Nifti1Image __all__ = ["ALFFBase"] diff --git a/junifer/markers/reho/_afni_reho.py b/junifer/markers/reho/_afni_reho.py index d681e0fc6..7f051ab88 100644 --- a/junifer/markers/reho/_afni_reho.py +++ b/junifer/markers/reho/_afni_reho.py @@ -21,7 +21,7 @@ from ...utils.singleton import Singleton if TYPE_CHECKING: - from nibabel import Nifti1Image + from nibabel.nifti1 import Nifti1Image __all__ = ["AFNIReHo"] diff --git a/junifer/markers/reho/_junifer_reho.py b/junifer/markers/reho/_junifer_reho.py index a82ddd662..545d17b84 100644 --- a/junifer/markers/reho/_junifer_reho.py +++ b/junifer/markers/reho/_junifer_reho.py @@ -25,7 +25,7 @@ from ...utils.singleton import Singleton if TYPE_CHECKING: - from nibabel import Nifti1Image + from nibabel.nifti1 import Nifti1Image __all__ = ["JuniferReHo"] diff --git a/junifer/markers/reho/reho_base.py b/junifer/markers/reho/reho_base.py index 6fcdcc403..394332467 100644 --- a/junifer/markers/reho/reho_base.py +++ b/junifer/markers/reho/reho_base.py @@ -22,7 +22,7 @@ from ._junifer_reho import JuniferReHo if TYPE_CHECKING: - from nibabel import Nifti1Image + from nibabel.nifti1 import Nifti1Image __all__ = ["ReHoBase"] diff --git a/junifer/preprocess/smoothing/_afni_smoothing.py b/junifer/preprocess/smoothing/_afni_smoothing.py index 80f7da691..6790b7b8b 100644 --- a/junifer/preprocess/smoothing/_afni_smoothing.py +++ b/junifer/preprocess/smoothing/_afni_smoothing.py @@ -17,7 +17,7 @@ from ...utils import logger, run_ext_cmd if TYPE_CHECKING: - from nibabel import Nifti1Image + from nibabel.nifti1 import Nifti1Image __all__ = ["AFNISmoothing"] diff --git a/junifer/preprocess/smoothing/_fsl_smoothing.py b/junifer/preprocess/smoothing/_fsl_smoothing.py index 65d67c098..b6c34ca86 100644 --- a/junifer/preprocess/smoothing/_fsl_smoothing.py +++ b/junifer/preprocess/smoothing/_fsl_smoothing.py @@ -16,7 +16,7 @@ from ...utils import logger, run_ext_cmd if TYPE_CHECKING: - from nibabel import Nifti1Image + from nibabel.nifti1 import Nifti1Image __all__ = ["FSLSmoothing"] diff --git a/junifer/preprocess/smoothing/_nilearn_smoothing.py b/junifer/preprocess/smoothing/_nilearn_smoothing.py index bfba8f3f3..304e700a4 100644 --- a/junifer/preprocess/smoothing/_nilearn_smoothing.py +++ b/junifer/preprocess/smoothing/_nilearn_smoothing.py @@ -18,7 +18,7 @@ from ...utils import logger if TYPE_CHECKING: - from nibabel import Nifti1Image + from nibabel.nifti1 import Nifti1Image __all__ = ["NilearnSmoothing"] -- 2.52.0 From 1dabebac7b6fa42d377361e7ee71b6192d2b5c75 Mon Sep 17 00:00:00 2001 From: Synchon Mandal Date: Tue, 12 Nov 2024 15:46:30 +0100 Subject: [PATCH 6/7] docs: update README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0a02207cf..b30d48439 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ The documentation is available at [https://juaml.github.io/junifer](https://juam * `preprocess`: Preprocessing module. * `storage`: Storage module. * `testing`: Testing components module. + * `typing`: Type hints module. * `utils`: Utilities module (e.g. logging). ## Installation -- 2.52.0 From c4e2c59694049ccd543f6b56705e5a0b23810029 Mon Sep 17 00:00:00 2001 From: Synchon Mandal Date: Tue, 12 Nov 2024 16:55:12 +0100 Subject: [PATCH 7/7] chore: add changelog 392.feature --- docs/changes/newsfragments/392.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/changes/newsfragments/392.feature diff --git a/docs/changes/newsfragments/392.feature b/docs/changes/newsfragments/392.feature new file mode 100644 index 000000000..d145cf6ee --- /dev/null +++ b/docs/changes/newsfragments/392.feature @@ -0,0 +1 @@ +Introduce ``junifer.typing`` sub-module to organise internal and external type hints by `Synchon Mandal`_ -- 2.52.0