junifer 0.0.7.dev72__py3-none-any.whl → 0.0.7.dev93__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
junifer/_version.py CHANGED
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '0.0.7.dev72'
21
- __version_tuple__ = version_tuple = (0, 0, 7, 'dev72')
20
+ __version__ = version = '0.0.7.dev93'
21
+ __version_tuple__ = version_tuple = (0, 0, 7, 'dev93')
junifer/api/decorators.py CHANGED
@@ -5,11 +5,19 @@
5
5
  # Synchon Mandal <s.mandal@fz-juelich.de>
6
6
  # License: AGPL
7
7
 
8
+ from ..data import DataDispatcher
8
9
  from ..pipeline import PipelineComponentRegistry
9
- from ..typing import DataGrabberLike, MarkerLike, PreprocessorLike, StorageLike
10
+ from ..typing import (
11
+ DataGrabberLike,
12
+ DataRegistryLike,
13
+ MarkerLike,
14
+ PreprocessorLike,
15
+ StorageLike,
16
+ )
10
17
 
11
18
 
12
19
  __all__ = [
20
+ "register_data_registry",
13
21
  "register_datagrabber",
14
22
  "register_datareader",
15
23
  "register_marker",
@@ -25,12 +33,12 @@ def register_datagrabber(klass: DataGrabberLike) -> DataGrabberLike:
25
33
 
26
34
  Parameters
27
35
  ----------
28
- klass: class
36
+ klass : class
29
37
  The class of the DataGrabber to register.
30
38
 
31
39
  Returns
32
40
  -------
33
- klass: class
41
+ class
34
42
  The unmodified input class.
35
43
 
36
44
  Notes
@@ -52,12 +60,12 @@ def register_datareader(klass: type) -> type:
52
60
 
53
61
  Parameters
54
62
  ----------
55
- klass: class
63
+ klass : class
56
64
  The class of the DataReader to register.
57
65
 
58
66
  Returns
59
67
  -------
60
- klass: class
68
+ class
61
69
  The unmodified input class.
62
70
 
63
71
  Notes
@@ -79,12 +87,12 @@ def register_preprocessor(klass: PreprocessorLike) -> PreprocessorLike:
79
87
 
80
88
  Parameters
81
89
  ----------
82
- klass: class
90
+ klass : class
83
91
  The class of the preprocessor to register.
84
92
 
85
93
  Returns
86
94
  -------
87
- klass: class
95
+ class
88
96
  The unmodified input class.
89
97
 
90
98
  """
@@ -102,12 +110,12 @@ def register_marker(klass: MarkerLike) -> MarkerLike:
102
110
 
103
111
  Parameters
104
112
  ----------
105
- klass: class
113
+ klass : class
106
114
  The class of the marker to register.
107
115
 
108
116
  Returns
109
117
  -------
110
- klass: class
118
+ class
111
119
  The unmodified input class.
112
120
 
113
121
  """
@@ -125,12 +133,12 @@ def register_storage(klass: StorageLike) -> StorageLike:
125
133
 
126
134
  Parameters
127
135
  ----------
128
- klass: class
136
+ klass : class
129
137
  The class of the storage to register.
130
138
 
131
139
  Returns
132
140
  -------
133
- klass: class
141
+ class
134
142
  The unmodified input class.
135
143
 
136
144
  """
@@ -139,3 +147,40 @@ def register_storage(klass: StorageLike) -> StorageLike:
139
147
  klass=klass,
140
148
  )
141
149
  return klass
150
+
151
+
152
+ def register_data_registry(name: str) -> DataRegistryLike:
153
+ """Registry registration decorator.
154
+
155
+ Registers the data registry as ``name``.
156
+
157
+ Parameters
158
+ ----------
159
+ name : str
160
+ The name of the data registry.
161
+
162
+ Returns
163
+ -------
164
+ class
165
+ The unmodified input class.
166
+
167
+ """
168
+
169
+ def decorator(klass: DataRegistryLike) -> DataRegistryLike:
170
+ """Actual decorator.
171
+
172
+ Parameters
173
+ ----------
174
+ klass : class
175
+ The class of the data registry to register.
176
+
177
+ Returns
178
+ -------
179
+ class
180
+ The unmodified input class.
181
+
182
+ """
183
+ DataDispatcher()[name] = klass
184
+ return klass
185
+
186
+ return decorator
@@ -0,0 +1,32 @@
1
+ """Provide tests for public decorators."""
2
+
3
+ # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
+ # License: AGPL
5
+
6
+ from junifer.api.decorators import register_data_registry
7
+ from junifer.data import BasePipelineDataRegistry, DataDispatcher
8
+
9
+
10
+ def test_register_data_registry() -> None:
11
+ """Test data registry registration."""
12
+
13
+ @register_data_registry("dumb")
14
+ class DumDum(BasePipelineDataRegistry):
15
+ def __init__(self):
16
+ super().__init__()
17
+
18
+ def register(self):
19
+ pass
20
+
21
+ def deregister(self):
22
+ pass
23
+
24
+ def load(self):
25
+ pass
26
+
27
+ def get(self):
28
+ pass
29
+
30
+ assert "dumb" in DataDispatcher()
31
+ _ = DataDispatcher().pop("dumb")
32
+ assert "dumb" not in DataDispatcher()
junifer/data/__init__.pyi CHANGED
@@ -1,5 +1,7 @@
1
1
  __all__ = [
2
+ "BasePipelineDataRegistry",
2
3
  "CoordinatesRegistry",
4
+ "DataDispatcher",
3
5
  "ParcellationRegistry",
4
6
  "MaskRegistry",
5
7
  "get_data",
@@ -12,11 +14,13 @@ __all__ = [
12
14
  "utils",
13
15
  ]
14
16
 
17
+ from .pipeline_data_registry_base import BasePipelineDataRegistry
15
18
  from .coordinates import CoordinatesRegistry
16
19
  from .parcellations import ParcellationRegistry
17
20
  from .masks import MaskRegistry
18
21
 
19
22
  from ._dispatch import (
23
+ DataDispatcher,
20
24
  get_data,
21
25
  list_data,
22
26
  load_data,
junifer/data/_dispatch.py CHANGED
@@ -3,6 +3,7 @@
3
3
  # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
4
  # License: AGPL
5
5
 
6
+ from collections.abc import Iterator, MutableMapping
6
7
  from pathlib import Path
7
8
  from typing import (
8
9
  TYPE_CHECKING,
@@ -18,13 +19,14 @@ from ..utils import raise_error
18
19
  from .coordinates import CoordinatesRegistry
19
20
  from .masks import MaskRegistry
20
21
  from .parcellations import ParcellationRegistry
22
+ from .pipeline_data_registry_base import BasePipelineDataRegistry
21
23
 
22
24
 
23
25
  if TYPE_CHECKING:
24
26
  from nibabel.nifti1 import Nifti1Image
25
27
 
26
-
27
28
  __all__ = [
29
+ "DataDispatcher",
28
30
  "deregister_data",
29
31
  "get_data",
30
32
  "list_data",
@@ -33,6 +35,77 @@ __all__ = [
33
35
  ]
34
36
 
35
37
 
38
+ class DataDispatcher(MutableMapping):
39
+ """Class for helping dynamic data dispatch."""
40
+
41
+ _instance = None
42
+
43
+ def __new__(cls):
44
+ # Make class singleton
45
+ if cls._instance is None:
46
+ cls._instance = super().__new__(cls)
47
+ # Set registries
48
+ cls._registries: dict[str, type[BasePipelineDataRegistry]] = {}
49
+ cls._builtin: dict[str, type[BasePipelineDataRegistry]] = {}
50
+ cls._external: dict[str, type[BasePipelineDataRegistry]] = {}
51
+ cls._builtin.update(
52
+ {
53
+ "coordinates": CoordinatesRegistry,
54
+ "parcellation": ParcellationRegistry,
55
+ "mask": MaskRegistry,
56
+ }
57
+ )
58
+ cls._registries.update(cls._builtin)
59
+ return cls._instance
60
+
61
+ def __getitem__(self, key: str) -> type[BasePipelineDataRegistry]:
62
+ return self._registries[key]
63
+
64
+ def __iter__(self) -> Iterator[str]:
65
+ return iter(self._registries)
66
+
67
+ def __len__(self) -> int:
68
+ return len(self._registries)
69
+
70
+ def __delitem__(self, key: str) -> None:
71
+ # Internal check
72
+ if key in self._builtin:
73
+ raise_error(f"Cannot delete in-built key: {key}")
74
+ # Non-existing key
75
+ if key not in self._external:
76
+ raise_error(klass=KeyError, msg=key)
77
+ # Update external
78
+ _ = self._external.pop(key)
79
+ # Update global
80
+ _ = self._registries.pop(key)
81
+
82
+ def __setitem__(
83
+ self, key: str, value: type[BasePipelineDataRegistry]
84
+ ) -> None:
85
+ # Internal check
86
+ if key in self._builtin:
87
+ raise_error(f"Cannot set value for in-built key: {key}")
88
+ # Value type check
89
+ if not issubclass(value, BasePipelineDataRegistry):
90
+ raise_error(f"Invalid value type: {type(value)}")
91
+ # Update external
92
+ self._external[key] = value
93
+ # Update global
94
+ self._registries[key] = value
95
+
96
+ def popitem():
97
+ """Not implemented."""
98
+ pass
99
+
100
+ def clear(self):
101
+ """Not implemented."""
102
+ pass
103
+
104
+ def setdefault(self, key: str, value=None):
105
+ """Not implemented."""
106
+ pass
107
+
108
+
36
109
  def get_data(
37
110
  kind: str,
38
111
  names: Union[
@@ -76,27 +149,16 @@ def get_data(
76
149
  If ``kind`` is invalid value.
77
150
 
78
151
  """
79
-
80
- if kind == "coordinates":
81
- return CoordinatesRegistry().get(
82
- coords=names,
83
- target_data=target_data,
84
- extra_input=extra_input,
85
- )
86
- elif kind == "parcellation":
87
- return ParcellationRegistry().get(
88
- parcellations=names,
89
- target_data=target_data,
90
- extra_input=extra_input,
91
- )
92
- elif kind == "mask":
93
- return MaskRegistry().get(
94
- masks=names,
152
+ try:
153
+ registry = DataDispatcher()[kind]
154
+ except KeyError:
155
+ raise_error(f"Unknown data kind: {kind}")
156
+ else:
157
+ return registry().get(
158
+ names,
95
159
  target_data=target_data,
96
160
  extra_input=extra_input,
97
161
  )
98
- else: # pragma: no cover
99
- raise_error(f"Unknown data kind: {kind}")
100
162
 
101
163
 
102
164
  def list_data(kind: str) -> list[str]:
@@ -119,14 +181,12 @@ def list_data(kind: str) -> list[str]:
119
181
 
120
182
  """
121
183
 
122
- if kind == "coordinates":
123
- return CoordinatesRegistry().list
124
- elif kind == "parcellation":
125
- return ParcellationRegistry().list
126
- elif kind == "mask":
127
- return MaskRegistry().list
128
- else: # pragma: no cover
184
+ try:
185
+ registry = DataDispatcher()[kind]
186
+ except KeyError:
129
187
  raise_error(f"Unknown data kind: {kind}")
188
+ else:
189
+ return registry().list
130
190
 
131
191
 
132
192
  def load_data(
@@ -165,15 +225,12 @@ def load_data(
165
225
  If ``kind`` is invalid value.
166
226
 
167
227
  """
168
-
169
- if kind == "coordinates":
170
- return CoordinatesRegistry().load(name=name)
171
- elif kind == "parcellation":
172
- return ParcellationRegistry().load(name=name, **kwargs)
173
- elif kind == "mask":
174
- return MaskRegistry().load(name=name, **kwargs)
175
- else: # pragma: no cover
228
+ try:
229
+ registry = DataDispatcher()[kind]
230
+ except KeyError:
176
231
  raise_error(f"Unknown data kind: {kind}")
232
+ else:
233
+ return registry().load(name, **kwargs)
177
234
 
178
235
 
179
236
  def register_data(
@@ -205,20 +262,14 @@ def register_data(
205
262
 
206
263
  """
207
264
 
208
- if kind == "coordinates":
209
- return CoordinatesRegistry().register(
210
- name=name, space=space, overwrite=overwrite, **kwargs
211
- )
212
- elif kind == "parcellation":
213
- return ParcellationRegistry().register(
214
- name=name, space=space, overwrite=overwrite, **kwargs
215
- )
216
- elif kind == "mask":
217
- return MaskRegistry().register(
265
+ try:
266
+ registry = DataDispatcher()[kind]
267
+ except KeyError:
268
+ raise_error(f"Unknown data kind: {kind}")
269
+ else:
270
+ return registry().register(
218
271
  name=name, space=space, overwrite=overwrite, **kwargs
219
272
  )
220
- else: # pragma: no cover
221
- raise_error(f"Unknown data kind: {kind}")
222
273
 
223
274
 
224
275
  def deregister_data(kind: str, name: str) -> None:
@@ -238,11 +289,9 @@ def deregister_data(kind: str, name: str) -> None:
238
289
 
239
290
  """
240
291
 
241
- if kind == "coordinates":
242
- return CoordinatesRegistry().deregister(name=name)
243
- elif kind == "parcellation":
244
- return ParcellationRegistry().deregister(name=name)
245
- elif kind == "mask":
246
- return MaskRegistry().deregister(name=name)
247
- else: # pragma: no cover
292
+ try:
293
+ registry = DataDispatcher()[kind]
294
+ except KeyError:
248
295
  raise_error(f"Unknown data kind: {kind}")
296
+ else:
297
+ return registry().deregister(name=name)
@@ -13,7 +13,6 @@ from junifer_data import get
13
13
  from numpy.typing import ArrayLike
14
14
 
15
15
  from ...utils import logger, raise_error
16
- from ...utils.singleton import Singleton
17
16
  from ..pipeline_data_registry_base import BasePipelineDataRegistry
18
17
  from ..utils import JUNIFER_DATA_PARAMS, get_dataset_path, get_native_warper
19
18
  from ._ants_coordinates_warper import ANTsCoordinatesWarper
@@ -23,7 +22,7 @@ from ._fsl_coordinates_warper import FSLCoordinatesWarper
23
22
  __all__ = ["CoordinatesRegistry"]
24
23
 
25
24
 
26
- class CoordinatesRegistry(BasePipelineDataRegistry, metaclass=Singleton):
25
+ class CoordinatesRegistry(BasePipelineDataRegistry):
27
26
  """Class for coordinates data registry.
28
27
 
29
28
  This class is a singleton and is used for managing available coordinates
@@ -24,7 +24,6 @@ from nilearn.masking import (
24
24
  )
25
25
 
26
26
  from ...utils import logger, raise_error
27
- from ...utils.singleton import Singleton
28
27
  from ..pipeline_data_registry_base import BasePipelineDataRegistry
29
28
  from ..template_spaces import get_template
30
29
  from ..utils import (
@@ -216,7 +215,7 @@ def compute_brain_mask(
216
215
  return nimg.new_img_like(target_data["data"], mask) # type: ignore
217
216
 
218
217
 
219
- class MaskRegistry(BasePipelineDataRegistry, metaclass=Singleton):
218
+ class MaskRegistry(BasePipelineDataRegistry):
220
219
  """Class for mask data registry.
221
220
 
222
221
  This class is a singleton and is used for managing available mask
@@ -16,7 +16,6 @@ import pandas as pd
16
16
  from junifer_data import get
17
17
 
18
18
  from ...utils import logger, raise_error, warn_with_log
19
- from ...utils.singleton import Singleton
20
19
  from ..pipeline_data_registry_base import BasePipelineDataRegistry
21
20
  from ..utils import (
22
21
  JUNIFER_DATA_PARAMS,
@@ -38,7 +37,7 @@ __all__ = [
38
37
  ]
39
38
 
40
39
 
41
- class ParcellationRegistry(BasePipelineDataRegistry, metaclass=Singleton):
40
+ class ParcellationRegistry(BasePipelineDataRegistry):
42
41
  """Class for parcellation data registry.
43
42
 
44
43
  This class is a singleton and is used for managing available parcellation
@@ -14,6 +14,7 @@ from nilearn.image import new_img_like, resample_to_img
14
14
  from numpy.testing import assert_array_almost_equal, assert_array_equal
15
15
 
16
16
  from junifer.data import (
17
+ deregister_data,
17
18
  get_data,
18
19
  list_data,
19
20
  load_data,
@@ -1245,3 +1246,9 @@ def test_get_multi_different_space() -> None:
1245
1246
  ],
1246
1247
  target_data=element_data["VBM_GM"],
1247
1248
  )
1249
+
1250
+
1251
+ def test_deregister() -> None:
1252
+ """Test parcellation deregistration."""
1253
+ deregister_data(kind="parcellation", name="testparc_3")
1254
+ assert "testparc_3" not in list_data(kind="parcellation")
@@ -0,0 +1,87 @@
1
+ """Provide tests for data dispatching."""
2
+
3
+ # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
+ # License: AGPL
5
+
6
+ import pytest
7
+
8
+ from junifer.data import (
9
+ BasePipelineDataRegistry,
10
+ deregister_data,
11
+ get_data,
12
+ list_data,
13
+ load_data,
14
+ register_data,
15
+ )
16
+ from junifer.data._dispatch import DataDispatcher
17
+
18
+
19
+ def test_dispatcher_addition_errors() -> None:
20
+ """Test registry addition errors."""
21
+ with pytest.raises(ValueError, match="Cannot set"):
22
+ DataDispatcher()["mask"] = dict
23
+
24
+ with pytest.raises(ValueError, match="Invalid"):
25
+ DataDispatcher()["masks"] = dict
26
+
27
+
28
+ def test_dispatcher_removal_errors() -> None:
29
+ """Test registry removal errors."""
30
+ with pytest.raises(ValueError, match="Cannot delete"):
31
+ _ = DataDispatcher().pop("mask")
32
+
33
+ with pytest.raises(KeyError, match="masks"):
34
+ del DataDispatcher()["masks"]
35
+
36
+
37
+ def test_dispatcher() -> None:
38
+ """Test registry addition and removal."""
39
+
40
+ class DumDum(BasePipelineDataRegistry):
41
+ def register():
42
+ pass
43
+
44
+ def deregister():
45
+ pass
46
+
47
+ def load():
48
+ pass
49
+
50
+ def get():
51
+ pass
52
+
53
+ DataDispatcher().update({"masks": DumDum})
54
+ assert "masks" in DataDispatcher()
55
+
56
+ _ = DataDispatcher().pop("masks")
57
+ assert "masks" not in DataDispatcher()
58
+
59
+
60
+ def test_get_data_error() -> None:
61
+ """Test error for get_data()."""
62
+ with pytest.raises(ValueError, match="Unknown data kind"):
63
+ get_data(kind="planet", names="neptune", target_data={})
64
+
65
+
66
+ def test_list_data_error() -> None:
67
+ """Test error for list_data()."""
68
+ with pytest.raises(ValueError, match="Unknown data kind"):
69
+ list_data(kind="planet")
70
+
71
+
72
+ def test_load_data_error() -> None:
73
+ """Test error for load_data()."""
74
+ with pytest.raises(ValueError, match="Unknown data kind"):
75
+ load_data(kind="planet", name="neptune")
76
+
77
+
78
+ def test_register_data_error() -> None:
79
+ """Test error for register_data()."""
80
+ with pytest.raises(ValueError, match="Unknown data kind"):
81
+ register_data(kind="planet", name="neptune", space="milkyway")
82
+
83
+
84
+ def test_deregister_data_error() -> None:
85
+ """Test error for deregister_data()."""
86
+ with pytest.raises(ValueError, match="Unknown data kind"):
87
+ deregister_data(kind="planet", name="neptune")
@@ -10,7 +10,11 @@ __all__ = [
10
10
  "DataladHCP1200",
11
11
  "MultipleDataGrabber",
12
12
  "DMCC13Benchmark",
13
+ "DataTypeManager",
14
+ "DataTypeSchema",
15
+ "OptionalTypeSchema",
13
16
  "PatternValidationMixin",
17
+ "register_data_type",
14
18
  ]
15
19
 
16
20
  # These 4 need to be in this order, otherwise it is a circular import
@@ -24,4 +28,10 @@ from .hcp1200 import HCP1200, DataladHCP1200
24
28
  from .multiple import MultipleDataGrabber
25
29
  from .dmcc13_benchmark import DMCC13Benchmark
26
30
 
27
- from .pattern_validation_mixin import PatternValidationMixin
31
+ from .pattern_validation_mixin import (
32
+ DataTypeManager,
33
+ DataTypeSchema,
34
+ OptionalTypeSchema,
35
+ PatternValidationMixin,
36
+ register_data_type,
37
+ )
@@ -3,71 +3,199 @@
3
3
  # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
4
  # License: AGPL
5
5
 
6
+ from collections.abc import Iterator, MutableMapping
7
+ from typing import TypedDict
8
+
6
9
  from ..typing import DataGrabberPatterns
7
10
  from ..utils import logger, raise_error, warn_with_log
8
11
 
9
12
 
10
- __all__ = ["PatternValidationMixin"]
11
-
12
-
13
- # Define schema for pattern-based datagrabber's patterns
14
- PATTERNS_SCHEMA = {
15
- "T1w": {
16
- "mandatory": ["pattern", "space"],
17
- "optional": {
18
- "mask": {"mandatory": ["pattern", "space"], "optional": []},
19
- },
20
- },
21
- "T2w": {
22
- "mandatory": ["pattern", "space"],
23
- "optional": {
24
- "mask": {"mandatory": ["pattern", "space"], "optional": []},
25
- },
26
- },
27
- "BOLD": {
28
- "mandatory": ["pattern", "space"],
29
- "optional": {
30
- "mask": {"mandatory": ["pattern", "space"], "optional": []},
31
- "confounds": {
32
- "mandatory": ["pattern", "format"],
33
- "optional": ["mappings"],
34
- },
35
- "reference": {"mandatory": ["pattern"], "optional": []},
36
- "prewarp_space": {"mandatory": [], "optional": []},
37
- },
38
- },
39
- "Warp": {
40
- "mandatory": ["pattern", "src", "dst", "warper"],
41
- "optional": {},
42
- },
43
- "VBM_GM": {
44
- "mandatory": ["pattern", "space"],
45
- "optional": {},
46
- },
47
- "VBM_WM": {
48
- "mandatory": ["pattern", "space"],
49
- "optional": {},
50
- },
51
- "VBM_CSF": {
52
- "mandatory": ["pattern", "space"],
53
- "optional": {},
54
- },
55
- "DWI": {
56
- "mandatory": ["pattern"],
57
- "optional": {},
58
- },
59
- "FreeSurfer": {
60
- "mandatory": ["pattern"],
61
- "optional": {
62
- "aseg": {"mandatory": ["pattern"], "optional": []},
63
- "norm": {"mandatory": ["pattern"], "optional": []},
64
- "lh_white": {"mandatory": ["pattern"], "optional": []},
65
- "rh_white": {"mandatory": ["pattern"], "optional": []},
66
- "lh_pial": {"mandatory": ["pattern"], "optional": []},
67
- "rh_pial": {"mandatory": ["pattern"], "optional": []},
68
- },
69
- },
70
- }
13
+ __all__ = [
14
+ "DataTypeManager",
15
+ "DataTypeSchema",
16
+ "OptionalTypeSchema",
17
+ "PatternValidationMixin",
18
+ "register_data_type",
19
+ ]
20
+
21
+
22
+ class OptionalTypeSchema(TypedDict):
23
+ """Optional type schema."""
24
+
25
+ mandatory: list[str]
26
+ optional: list[str]
27
+
28
+
29
+ class DataTypeSchema(TypedDict):
30
+ """Data type schema."""
31
+
32
+ mandatory: list[str]
33
+ optional: dict[str, OptionalTypeSchema]
34
+
35
+
36
+ class DataTypeManager(MutableMapping):
37
+ """Class for managing data types."""
38
+
39
+ _instance = None
40
+
41
+ def __new__(cls):
42
+ """Overridden to make the class singleton."""
43
+ # Make class singleton
44
+ if cls._instance is None:
45
+ cls._instance = super().__new__(cls)
46
+ # Set global schema
47
+ cls._global: dict[str, DataTypeSchema] = {}
48
+ cls._builtin: dict[str, DataTypeSchema] = {}
49
+ cls._external: dict[str, DataTypeSchema] = {}
50
+ cls._builtin.update(
51
+ {
52
+ "T1w": {
53
+ "mandatory": ["pattern", "space"],
54
+ "optional": {
55
+ "mask": {
56
+ "mandatory": ["pattern", "space"],
57
+ "optional": [],
58
+ },
59
+ },
60
+ },
61
+ "T2w": {
62
+ "mandatory": ["pattern", "space"],
63
+ "optional": {
64
+ "mask": {
65
+ "mandatory": ["pattern", "space"],
66
+ "optional": [],
67
+ },
68
+ },
69
+ },
70
+ "BOLD": {
71
+ "mandatory": ["pattern", "space"],
72
+ "optional": {
73
+ "mask": {
74
+ "mandatory": ["pattern", "space"],
75
+ "optional": [],
76
+ },
77
+ "confounds": {
78
+ "mandatory": ["pattern", "format"],
79
+ "optional": ["mappings"],
80
+ },
81
+ "reference": {
82
+ "mandatory": ["pattern"],
83
+ "optional": [],
84
+ },
85
+ "prewarp_space": {"mandatory": [], "optional": []},
86
+ },
87
+ },
88
+ "Warp": {
89
+ "mandatory": ["pattern", "src", "dst", "warper"],
90
+ "optional": {},
91
+ },
92
+ "VBM_GM": {
93
+ "mandatory": ["pattern", "space"],
94
+ "optional": {},
95
+ },
96
+ "VBM_WM": {
97
+ "mandatory": ["pattern", "space"],
98
+ "optional": {},
99
+ },
100
+ "VBM_CSF": {
101
+ "mandatory": ["pattern", "space"],
102
+ "optional": {},
103
+ },
104
+ "DWI": {
105
+ "mandatory": ["pattern"],
106
+ "optional": {},
107
+ },
108
+ "FreeSurfer": {
109
+ "mandatory": ["pattern"],
110
+ "optional": {
111
+ "aseg": {"mandatory": ["pattern"], "optional": []},
112
+ "norm": {"mandatory": ["pattern"], "optional": []},
113
+ "lh_white": {
114
+ "mandatory": ["pattern"],
115
+ "optional": [],
116
+ },
117
+ "rh_white": {
118
+ "mandatory": ["pattern"],
119
+ "optional": [],
120
+ },
121
+ "lh_pial": {
122
+ "mandatory": ["pattern"],
123
+ "optional": [],
124
+ },
125
+ "rh_pial": {
126
+ "mandatory": ["pattern"],
127
+ "optional": [],
128
+ },
129
+ },
130
+ },
131
+ }
132
+ )
133
+ cls._global.update(cls._builtin)
134
+ return cls._instance
135
+
136
+ def __getitem__(self, key: str) -> DataTypeSchema:
137
+ """Retrieve schema for ``key``."""
138
+ return self._global[key]
139
+
140
+ def __iter__(self) -> Iterator[str]:
141
+ """Iterate over data types."""
142
+ return iter(self._global)
143
+
144
+ def __len__(self) -> int:
145
+ """Get data type count."""
146
+ return len(self._global)
147
+
148
+ def __delitem__(self, key: str) -> None:
149
+ """Remove schema for ``key``."""
150
+ # Internal check
151
+ if key in self._builtin:
152
+ raise_error(f"Cannot delete in-built key: {key}")
153
+ # Non-existing key
154
+ if key not in self._external:
155
+ raise_error(klass=KeyError, msg=key)
156
+ # Update external
157
+ _ = self._external.pop(key)
158
+ # Update global
159
+ _ = self._global.pop(key)
160
+
161
+ def __setitem__(self, key: str, value: DataTypeSchema) -> None:
162
+ """Update ``key`` with ``value``."""
163
+ # Internal check
164
+ if key in self._builtin:
165
+ raise_error(f"Cannot set value for in-built key: {key}")
166
+ # Value type check
167
+ if not isinstance(value, dict):
168
+ raise_error(f"Invalid value type: {type(value)}")
169
+ # Update external
170
+ self._external[key] = value
171
+ # Update global
172
+ self._global[key] = value
173
+
174
+ def popitem():
175
+ """Not implemented."""
176
+ pass
177
+
178
+ def clear(self):
179
+ """Not implemented."""
180
+ pass
181
+
182
+ def setdefault(self, key: str, value=None):
183
+ """Not implemented."""
184
+ pass
185
+
186
+
187
+ def register_data_type(name: str, schema: DataTypeSchema) -> None:
188
+ """Register custom data type.
189
+
190
+ Parameters
191
+ ----------
192
+ name : str
193
+ The data type name.
194
+ schema : DataTypeSchema
195
+ The data type schema.
196
+
197
+ """
198
+ DataTypeManager()[name] = schema
71
199
 
72
200
 
73
201
  class PatternValidationMixin:
@@ -311,12 +439,13 @@ class PatternValidationMixin:
311
439
  msg="`patterns` must contain all `types`", klass=ValueError
312
440
  )
313
441
  # Check against schema
442
+ dtype_mgr = DataTypeManager()
314
443
  for dtype_key, dtype_val in patterns.items():
315
444
  # Check if valid data type is provided
316
- if dtype_key not in PATTERNS_SCHEMA:
445
+ if dtype_key not in dtype_mgr:
317
446
  raise_error(
318
447
  f"Unknown data type: {dtype_key}, "
319
- f"should be one of: {list(PATTERNS_SCHEMA.keys())}"
448
+ f"should be one of: {list(dtype_mgr.keys())}"
320
449
  )
321
450
  # Conditional for list dtype vals like Warp
322
451
  if isinstance(dtype_val, list):
@@ -324,14 +453,14 @@ class PatternValidationMixin:
324
453
  # Check mandatory keys for data type
325
454
  self._validate_mandatory_keys(
326
455
  keys=list(entry),
327
- schema=PATTERNS_SCHEMA[dtype_key]["mandatory"],
456
+ schema=dtype_mgr[dtype_key]["mandatory"],
328
457
  data_type=f"{dtype_key}.{idx}",
329
458
  partial_pattern_ok=partial_pattern_ok,
330
459
  )
331
460
  # Check optional keys for data type
332
- for optional_key, optional_val in PATTERNS_SCHEMA[
333
- dtype_key
334
- ]["optional"].items():
461
+ for optional_key, optional_val in dtype_mgr[dtype_key][
462
+ "optional"
463
+ ].items():
335
464
  if optional_key not in entry:
336
465
  logger.debug(
337
466
  f"Optional key: `{optional_key}` missing for "
@@ -344,12 +473,12 @@ class PatternValidationMixin:
344
473
  )
345
474
  # Set nested type name for easier access
346
475
  nested_dtype = f"{dtype_key}.{idx}.{optional_key}"
347
- nested_mandatory_keys_schema = PATTERNS_SCHEMA[
476
+ nested_mandatory_keys_schema = dtype_mgr[
348
477
  dtype_key
349
478
  ]["optional"][optional_key]["mandatory"]
350
- nested_optional_keys_schema = PATTERNS_SCHEMA[
351
- dtype_key
352
- ]["optional"][optional_key]["optional"]
479
+ nested_optional_keys_schema = dtype_mgr[dtype_key][
480
+ "optional"
481
+ ][optional_key]["optional"]
353
482
  # Check mandatory keys for nested type
354
483
  self._validate_mandatory_keys(
355
484
  keys=list(optional_val["mandatory"]),
@@ -392,10 +521,8 @@ class PatternValidationMixin:
392
521
  self._identify_stray_keys(
393
522
  keys=list(entry.keys()),
394
523
  schema=(
395
- PATTERNS_SCHEMA[dtype_key]["mandatory"]
396
- + list(
397
- PATTERNS_SCHEMA[dtype_key]["optional"].keys()
398
- )
524
+ dtype_mgr[dtype_key]["mandatory"]
525
+ + list(dtype_mgr[dtype_key]["optional"].keys())
399
526
  ),
400
527
  data_type=dtype_key,
401
528
  )
@@ -412,12 +539,12 @@ class PatternValidationMixin:
412
539
  # Check mandatory keys for data type
413
540
  self._validate_mandatory_keys(
414
541
  keys=list(dtype_val),
415
- schema=PATTERNS_SCHEMA[dtype_key]["mandatory"],
542
+ schema=dtype_mgr[dtype_key]["mandatory"],
416
543
  data_type=dtype_key,
417
544
  partial_pattern_ok=partial_pattern_ok,
418
545
  )
419
546
  # Check optional keys for data type
420
- for optional_key, optional_val in PATTERNS_SCHEMA[dtype_key][
547
+ for optional_key, optional_val in dtype_mgr[dtype_key][
421
548
  "optional"
422
549
  ].items():
423
550
  if optional_key not in dtype_val:
@@ -432,12 +559,12 @@ class PatternValidationMixin:
432
559
  )
433
560
  # Set nested type name for easier access
434
561
  nested_dtype = f"{dtype_key}.{optional_key}"
435
- nested_mandatory_keys_schema = PATTERNS_SCHEMA[
436
- dtype_key
437
- ]["optional"][optional_key]["mandatory"]
438
- nested_optional_keys_schema = PATTERNS_SCHEMA[
439
- dtype_key
440
- ]["optional"][optional_key]["optional"]
562
+ nested_mandatory_keys_schema = dtype_mgr[dtype_key][
563
+ "optional"
564
+ ][optional_key]["mandatory"]
565
+ nested_optional_keys_schema = dtype_mgr[dtype_key][
566
+ "optional"
567
+ ][optional_key]["optional"]
441
568
  # Check mandatory keys for nested type
442
569
  self._validate_mandatory_keys(
443
570
  keys=list(optional_val["mandatory"]),
@@ -476,8 +603,8 @@ class PatternValidationMixin:
476
603
  self._identify_stray_keys(
477
604
  keys=list(dtype_val.keys()),
478
605
  schema=(
479
- PATTERNS_SCHEMA[dtype_key]["mandatory"]
480
- + list(PATTERNS_SCHEMA[dtype_key]["optional"].keys())
606
+ dtype_mgr[dtype_key]["mandatory"]
607
+ + list(dtype_mgr[dtype_key]["optional"].keys())
481
608
  ),
482
609
  data_type=dtype_key,
483
610
  )
@@ -9,7 +9,110 @@ from typing import Union
9
9
 
10
10
  import pytest
11
11
 
12
- from junifer.datagrabber.pattern_validation_mixin import PatternValidationMixin
12
+ from junifer.datagrabber.pattern_validation_mixin import (
13
+ DataTypeManager,
14
+ DataTypeSchema,
15
+ PatternValidationMixin,
16
+ register_data_type,
17
+ )
18
+
19
+
20
+ def test_dtype_mgr_addition_errors() -> None:
21
+ """Test data type manager addition errors."""
22
+ with pytest.raises(ValueError, match="Cannot set"):
23
+ dtype_schema: DataTypeSchema = {
24
+ "mandatory": ["pattern"],
25
+ "optional": {},
26
+ }
27
+ DataTypeManager()["T1w"] = dtype_schema
28
+
29
+ with pytest.raises(ValueError, match="Invalid"):
30
+ DataTypeManager()["DType"] = ""
31
+
32
+
33
+ def test_dtype_mgr_removal_errors() -> None:
34
+ """Test data type manager removal errors."""
35
+ with pytest.raises(ValueError, match="Cannot delete"):
36
+ _ = DataTypeManager().pop("T1w")
37
+
38
+ with pytest.raises(KeyError, match="DType"):
39
+ del DataTypeManager()["DType"]
40
+
41
+
42
+ @pytest.mark.parametrize(
43
+ "dtype",
44
+ [
45
+ {
46
+ "mandatory": ["pattern"],
47
+ "optional": {},
48
+ },
49
+ {
50
+ "mandatory": ["pattern"],
51
+ "optional": {
52
+ "subtype": {
53
+ "mandatory": [],
54
+ "optional": [],
55
+ }
56
+ },
57
+ },
58
+ {
59
+ "mandatory": ["pattern"],
60
+ "optional": {
61
+ "subtype": {
62
+ "mandatory": ["pattern"],
63
+ "optional": [],
64
+ }
65
+ },
66
+ },
67
+ {
68
+ "mandatory": ["pattern"],
69
+ "optional": {
70
+ "subtype": {
71
+ "mandatory": ["pattern"],
72
+ "optional": ["pattern"],
73
+ }
74
+ },
75
+ },
76
+ ],
77
+ )
78
+ def test_dtype_mgr(dtype: DataTypeSchema) -> None:
79
+ """Test data type manager addition and removal.
80
+
81
+ Parameters
82
+ ----------
83
+ dtype : DataTypeSchema
84
+ The parametrized schema.
85
+
86
+ """
87
+
88
+ DataTypeManager().update({"DType": dtype})
89
+ assert "DType" in DataTypeManager()
90
+
91
+ _ = DataTypeManager().pop("DType")
92
+ assert "DType" not in DataTypeManager()
93
+
94
+
95
+ def test_register_data_type() -> None:
96
+ """Test data type registration."""
97
+
98
+ dtype_schema: DataTypeSchema = {
99
+ "mandatory": ["pattern"],
100
+ "optional": {
101
+ "mask": {
102
+ "mandatory": ["pattern"],
103
+ "optional": [],
104
+ },
105
+ },
106
+ }
107
+
108
+ register_data_type(
109
+ name="dtype",
110
+ schema=dtype_schema,
111
+ )
112
+
113
+ assert "dtype" in DataTypeManager()
114
+ _ = DataTypeManager().pop("dtype")
115
+ assert "dumb" not in DataTypeManager()
13
116
 
14
117
 
15
118
  @pytest.mark.parametrize(
@@ -1,5 +1,6 @@
1
1
  __all__ = [
2
2
  "DataGrabberLike",
3
+ "DataRegistryLike",
3
4
  "PreprocessorLike",
4
5
  "MarkerLike",
5
6
  "StorageLike",
@@ -16,6 +17,7 @@ __all__ = [
16
17
 
17
18
  from ._typing import (
18
19
  DataGrabberLike,
20
+ DataRegistryLike,
19
21
  PreprocessorLike,
20
22
  MarkerLike,
21
23
  StorageLike,
junifer/typing/_typing.py CHANGED
@@ -11,6 +11,7 @@ from typing import (
11
11
 
12
12
 
13
13
  if TYPE_CHECKING:
14
+ from ..data import BasePipelineDataRegistry
14
15
  from ..datagrabber import BaseDataGrabber
15
16
  from ..datareader import DefaultDataReader
16
17
  from ..markers import BaseMarker
@@ -23,6 +24,7 @@ __all__ = [
23
24
  "ConfigVal",
24
25
  "DataGrabberLike",
25
26
  "DataGrabberPatterns",
27
+ "DataRegistryLike",
26
28
  "Dependencies",
27
29
  "Element",
28
30
  "Elements",
@@ -35,6 +37,7 @@ __all__ = [
35
37
  ]
36
38
 
37
39
 
40
+ DataRegistryLike = type["BasePipelineDataRegistry"]
38
41
  DataGrabberLike = type["BaseDataGrabber"]
39
42
  PreprocessorLike = type["BasePreprocessor"]
40
43
  MarkerLike = type["BaseMarker"]
@@ -61,7 +64,7 @@ ConditionalDependencies = Sequence[
61
64
  ExternalDependencies = Sequence[MutableMapping[str, Union[str, Sequence[str]]]]
62
65
  MarkerInOutMappings = MutableMapping[str, MutableMapping[str, str]]
63
66
  DataGrabberPatterns = dict[
64
- str, Union[dict[str, str], Sequence[dict[str, str]]]
67
+ str, Union[dict[str, str], list[dict[str, str]]]
65
68
  ]
66
69
  ConfigVal = Union[bool, int, float, str]
67
70
  Element = Union[str, tuple[str, ...]]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: junifer
3
- Version: 0.0.7.dev72
3
+ Version: 0.0.7.dev93
4
4
  Summary: JUelich NeuroImaging FEature extractoR
5
5
  Author-email: Fede Raimondo <f.raimondo@fz-juelich.de>, Synchon Mandal <s.mandal@fz-juelich.de>
6
6
  Maintainer-email: Fede Raimondo <f.raimondo@fz-juelich.de>, Synchon Mandal <s.mandal@fz-juelich.de>
@@ -1,12 +1,12 @@
1
1
  junifer/__init__.py,sha256=2McgH1yNue6Z1V26-uN_mfMjbTcx4CLhym-DMBl5xA4,266
2
2
  junifer/__init__.pyi,sha256=SsTvgq2Dod6UqJN96GH1lCphH6hJQQurEJHGNhHjGUI,508
3
- junifer/_version.py,sha256=LYWWm9KxYBr--JmpK7VCe37ywBK4F9KtSMviNQt4mQw,526
3
+ junifer/_version.py,sha256=vFYsjG-TWfjglJG7fH8rtbhQ3pjvXxlnFjXQw4toOfM,526
4
4
  junifer/conftest.py,sha256=PWYkkRDU8ly2lYwv7VBKMHje4et6HX7Yey3Md_I2KbA,613
5
5
  junifer/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  junifer/stats.py,sha256=e9aaagMGtgpRfW3Wdpz9ocpnYld1IWylCDcjFUgX9Mk,6225
7
7
  junifer/api/__init__.py,sha256=aAXW_KAEGQ8aAP5Eni2G1R4MWBF7UgjKOgM6akLuJco,252
8
8
  junifer/api/__init__.pyi,sha256=UJu55ApMFd43N0xlQyNKrYpCdzqhAxA3Jjaj0ETwCXU,169
9
- junifer/api/decorators.py,sha256=rBkoqHt_lKUb9b_ctbKNPk5E2XGHCiYSsMm3PrxDjdw,2853
9
+ junifer/api/decorators.py,sha256=hBmJbJIedXvCxzvxWBQond3Nu9oSTd2e7dvJ_QZ9zF0,3635
10
10
  junifer/api/functions.py,sha256=LXKPqsfWINq1iSUShdryGB8hPOyyydc1ldHfr68bP20,14226
11
11
  junifer/api/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
12
  junifer/api/queue_context/__init__.py,sha256=glr8x4aMm4EvVrHywDIlugdNlwD1RzqV2FTDNPqYQZ4,204
@@ -40,6 +40,7 @@ junifer/api/res/fsl/flirt,sha256=tSjiUco8ui8AbHD7mTzChEwbR0Rf_4iJTgzYTPF_WuQ,42
40
40
  junifer/api/res/fsl/img2imgcoord,sha256=Zmaw3oJYrEltcXiPyEubXry9ppAq3SND52tdDWGgeZk,49
41
41
  junifer/api/res/fsl/run_fsl_docker.sh,sha256=pq-fcNdLuvHzVIQePN4GebZGlcE2UF-xj5rBIqAMz4g,1122
42
42
  junifer/api/res/fsl/std2imgcoord,sha256=-X5wRH6XMl0yqnTACJX6MFhO8DFOEWg42MHRxGvimXg,49
43
+ junifer/api/tests/test_decorators.py,sha256=GN4wSRDJncqa1Jz9krNY_Ls9e6ge9xaGyOpaiSSXibk,759
43
44
  junifer/api/tests/test_functions.py,sha256=HcJIBCtcgL1xJlDwtGHrGOWBMjXgCoAFoVxQW6n2Tds,20676
44
45
  junifer/cli/__init__.py,sha256=LRmpmMe0DdZKYZTV61onUiLLxYZ_ZYSfmRbH55bBJMg,500
45
46
  junifer/cli/__init__.pyi,sha256=PiV4znUnzSeuSSJGz-RT8N21PiMqoSMwYcypi7nt2Js,40
@@ -71,8 +72,8 @@ junifer/configs/juseless/datagrabbers/tests/test_ixi_vbm.py,sha256=8jxpNZelXwpJG
71
72
  junifer/configs/juseless/datagrabbers/tests/test_ucla.py,sha256=l-1y_m6NJo7JExhyIzp-vajUfiqiofX69YUOrRHIFKw,3246
72
73
  junifer/configs/juseless/datagrabbers/tests/test_ukb_vbm.py,sha256=b9hjc1mgO--PSRC3id2EzzfE2yWNsuZ2UI47a6sfGZU,1025
73
74
  junifer/data/__init__.py,sha256=xJDI2QKtdjcNzpd1oVFM3guh1SFHM6jKstl7pFmzOuk,267
74
- junifer/data/__init__.pyi,sha256=qYszjUYcbFi_2zO23MnbA2HhTW-Ad2oh1pqPQYd6yt0,542
75
- junifer/data/_dispatch.py,sha256=TZmz9CS9GNKu1fGk9H0SY_G45P0kCU1XY0xBYxEqm4A,6270
75
+ junifer/data/__init__.pyi,sha256=yt6gNTY8fgv9O5HjUqEHdKkO7Oo3q4dVp-aeqP4q5PY,682
76
+ junifer/data/_dispatch.py,sha256=l1UbmSQyrAVzfYopaijUFIkbHntFdIxsA8RpRHjvcf0,7519
76
77
  junifer/data/pipeline_data_registry_base.py,sha256=G8bE3WTj4D_rKC4ZKZe6E48Sd96CGea1PS3SxmTgGK4,2010
77
78
  junifer/data/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
78
79
  junifer/data/template_spaces.py,sha256=7LcQbUV_SWCic-TtETCejgat-BxxFDxZFm5z80rRZ-M,4661
@@ -80,32 +81,33 @@ junifer/data/utils.py,sha256=zVqlkc2jXFDv1jx8plXBHRL6y0h1eR_XzH7fkTJ6ric,3978
80
81
  junifer/data/coordinates/__init__.py,sha256=ffM8rwcHLgHAWixJbKrATrbUKzX940V1UF6RAxZdUMg,186
81
82
  junifer/data/coordinates/__init__.pyi,sha256=Z-Ti5XD3HigkZ8uYN6oYsLqw40-F1GvTVQ5QAy08Wng,88
82
83
  junifer/data/coordinates/_ants_coordinates_warper.py,sha256=9nIdg4B5EMje8s30n_8Dl7eYko3HmVJ8jyZpXETg8Sk,2976
83
- junifer/data/coordinates/_coordinates.py,sha256=DHjSPaA3ntlP85SERefqkiGkq-rITrR9dpONj4oQwgc,13365
84
+ junifer/data/coordinates/_coordinates.py,sha256=l-nu-eGdW2Cp4eDmnrSsuWE-zcj55apPab5pTt07SwU,13303
84
85
  junifer/data/coordinates/_fsl_coordinates_warper.py,sha256=fxxvsiq-hSeP_PDokMHJSxlyffMugzSDUHhKzuU7Vg4,2429
85
86
  junifer/data/coordinates/tests/test_coordinates.py,sha256=JG045I7l5zcxGRQMbZZTrJY0TI5ZKaJ_szGMB6j1ZRI,4623
86
87
  junifer/data/masks/__init__.py,sha256=eEEhHglyVEx1LrqwXjq3cOmjf4sTsgBstRx5-k7zIQU,180
87
88
  junifer/data/masks/__init__.pyi,sha256=lcgr8gmWDPibC4RxnWBXb8DDpIkO73Aax09u6VXiJJI,114
88
89
  junifer/data/masks/_ants_mask_warper.py,sha256=YJYVuD4QkgFwUSs1edt2rrqfHYHaIR1u85HSeQE4GUk,5825
89
90
  junifer/data/masks/_fsl_mask_warper.py,sha256=7-Aw4m9GA7ZLqB26jjuKYJUJSv9V11DfPFNBbb5caSE,2877
90
- junifer/data/masks/_masks.py,sha256=c30OPW01jfiZT4ExM2uZdoRvQ-VeTcXEk3R68EUDoHc,28664
91
+ junifer/data/masks/_masks.py,sha256=hOQ_VpXW8HvOfpd7-bxxvPClEn5WT3WQHro2Ofrtna8,28602
91
92
  junifer/data/masks/tests/test_masks.py,sha256=VK3IenIwhaYpbESe0pOjb40OKE6rcRlw8ddsBxSRfyU,16688
92
93
  junifer/data/parcellations/__init__.py,sha256=6-Ysil3NyZ69V6rWx4RO15_d-iDKizfbHuxSjsHNt24,188
93
94
  junifer/data/parcellations/__init__.pyi,sha256=lhBHTbMDizzqUqVHrx2eyfPFodrTBgMFeTgxfESSkQ8,140
94
95
  junifer/data/parcellations/_ants_parcellation_warper.py,sha256=LIfeIAv3bFQbIrl6Cr7RU2RdkA-c2G6qURIBUe5MJCQ,5826
95
96
  junifer/data/parcellations/_fsl_parcellation_warper.py,sha256=lmZDPv2fMjOnbJ0z2d3K9S7QH2bgYd5bXbzxNDUR5NY,2699
96
- junifer/data/parcellations/_parcellations.py,sha256=bby15ZET8AhudtUg74CAMz_eKRMCUbRGmKSOfwGl-5o,48490
97
- junifer/data/parcellations/tests/test_parcellations.py,sha256=898lhEpmVW-KcjD2Wj--oe_AU8qOSmK78rZrbj86vpY,37324
97
+ junifer/data/parcellations/_parcellations.py,sha256=e5Cd6VptKNZaqmAnfuhfMPeb48utimAkq5h4JioaB5w,48428
98
+ junifer/data/parcellations/tests/test_parcellations.py,sha256=s3TtsXTw7wEb-FvW0pFX2QcIXjp9IwlgjtM8X95rz_8,37544
98
99
  junifer/data/tests/test_data_utils.py,sha256=6-UQ7HDZ7_zA7iQalzk29KJBdftQMVyqKsQ0tx1URkE,1062
100
+ junifer/data/tests/test_dispatch.py,sha256=bm4R0E8gs_XpJ6B5lfWFXjle7PmDjaX7Wu0L6mEU33w,2315
99
101
  junifer/data/tests/test_template_spaces.py,sha256=ZEicEcLqOJ-NpuBZ5SYh4yZ0xZRkhYHnYXiC_YSxjrY,3219
100
102
  junifer/datagrabber/__init__.py,sha256=EHIK-lbjuvkt0V8ypFvLSt85OAAXSkaxBmVlCbNNz8M,323
101
- junifer/datagrabber/__init__.pyi,sha256=zOQE4TaCKXBTHnNqgmECtsszWIOHYiQ1CUEeXXFU9F4,832
103
+ junifer/datagrabber/__init__.pyi,sha256=4Eydc8RO4TN8TLRDq68cdbJPQMxGEynQwU2bmmWStLg,1027
102
104
  junifer/datagrabber/base.py,sha256=Llr5bHyHovkySI-bzxoQ1TklEF6WOaNRN9D_srqQvYM,6661
103
105
  junifer/datagrabber/datalad_base.py,sha256=52T2DbqDGOxiKSESBESzElrVJ3WihLWrrGlQewSvYOs,12616
104
106
  junifer/datagrabber/dmcc13_benchmark.py,sha256=VMyiwvkr4qSvzBICSksPPKOI2w_WVo06H89Url-hrNs,12819
105
107
  junifer/datagrabber/multiple.py,sha256=4tCOzojs3hoG7daHJJ7HUsx15atWR5nTmyP0S0__aig,6666
106
108
  junifer/datagrabber/pattern.py,sha256=hZxXc59qFGiH710aZkcVgt-JcvVjuR-EMmQ1_QFAoHM,18724
107
109
  junifer/datagrabber/pattern_datalad.py,sha256=7jY-0Xw0G-mKG0BgXNTQPuS-KPnpFhvqfVOZtD6Yfcc,4567
108
- junifer/datagrabber/pattern_validation_mixin.py,sha256=3MwpeUePm8eGgbe-J2kTWs9x5bk1SR3nhojHwN95SXM,19368
110
+ junifer/datagrabber/pattern_validation_mixin.py,sha256=UpeSy9jNtJ_5OL5IqlLIFPOMg0SFTHcOTpW3DlepE9g,23696
109
111
  junifer/datagrabber/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
110
112
  junifer/datagrabber/aomic/__init__.py,sha256=ATxzXq9NBPmWowTMuL77zqrmIbbnk0Wd1iXtXCP3XDg,266
111
113
  junifer/datagrabber/aomic/__init__.pyi,sha256=Rp6C075fZDdKY8VIq508_g4NhVj8bWzR6zb9yln761Q,189
@@ -128,7 +130,7 @@ junifer/datagrabber/tests/test_dmcc13_benchmark.py,sha256=h5zLrcP7BbSCeGLt2VfCsi
128
130
  junifer/datagrabber/tests/test_multiple.py,sha256=tZBQhlEiSE1PeQ5E3TtuVgsHENquna9t39p54AJ-O5w,9963
129
131
  junifer/datagrabber/tests/test_pattern.py,sha256=H55jYRPfT3rMsoIQOAnWJgw3nGrkU7m2xFa3-ed6NQE,9527
130
132
  junifer/datagrabber/tests/test_pattern_datalad.py,sha256=HJ3dQ3XSlMZ3UT1w2b2xpdPqvfmNxRWmla9zhRejWYI,6483
131
- junifer/datagrabber/tests/test_pattern_validation_mixin.py,sha256=KU3xha3Mo7IX_5Tp4RL5awvEzZrX43OmrRFjeqMYVgk,7498
133
+ junifer/datagrabber/tests/test_pattern_validation_mixin.py,sha256=yzUBRB4it_2BCNcp8syh5n3WejRRI6YfMg5T-p4_IkM,9982
132
134
  junifer/datareader/__init__.py,sha256=CDWjL4PQthskxWX5d0ASro6YIfTT1Tb7ZmyDllWWZso,318
133
135
  junifer/datareader/__init__.pyi,sha256=VOqhh-C3-eqapHVR7-F9Ulc_6iyHTb35XLoGb2DCRaA,72
134
136
  junifer/datareader/default.py,sha256=q8aXHlBzLtRtgM2z3JWIsB-daSZncr33mliZlV5RzdM,6733
@@ -305,8 +307,8 @@ junifer/testing/tests/test_testing_registry.py,sha256=MK4a_q4MHieCvYhnhuPm_dH76l
305
307
  junifer/tests/test_main.py,sha256=GMff7jlisGM9_FsiUwWDte43j-KQJGFRYZpwRRqTkd8,373
306
308
  junifer/tests/test_stats.py,sha256=NljoGFu2JOPADbi9W0WeUHwpf8nZSdOkcCgCv-Z1fY4,4149
307
309
  junifer/typing/__init__.py,sha256=e0UbuxozXUIxz8h8pLokMOxZV629Q1lnA7vvgm95WF0,215
308
- junifer/typing/__init__.pyi,sha256=GRGfrnReP1ROtQM6eT0EpFjmE-v-pCJuBiQZMXCVTsE,594
309
- junifer/typing/_typing.py,sha256=2D7ibO5OB3yTgpjI1IV_QorZ6b-ZEQVPQE-z2qxis9I,1663
310
+ junifer/typing/__init__.pyi,sha256=5jzVAkras38Eou5abUvdP1AXhbpCSnPAllLx88YuPB8,640
311
+ junifer/typing/_typing.py,sha256=JogiI9wCZWHuqgTaZarjk89aA5pR0yTvFx2JfheLT_Y,1783
310
312
  junifer/utils/__init__.py,sha256=I3tYaePAD_ZEU-36-TJ_OYeqW_aMmi5MZ3jmqie6RfU,260
311
313
  junifer/utils/__init__.pyi,sha256=CMb4rq1VcQ00IRuiBFfAWu07Vb-vA4qtVLAoY0ll-bA,422
312
314
  junifer/utils/_config.py,sha256=cfxyv1bfklID2atQseu6y3J7mZrCXPwnGEfBSImG9CM,3054
@@ -320,10 +322,10 @@ junifer/utils/tests/test_config.py,sha256=7ltIXuwb_W4Mv_1dxQWyiyM10XgUAfsWKV6D_i
320
322
  junifer/utils/tests/test_fs.py,sha256=WQS7cKlKEZ742CIuiOYYpueeAhY9PqlastfDVpVVtvE,923
321
323
  junifer/utils/tests/test_helpers.py,sha256=k5qqfxK8dFyuewTJyR1Qn6-nFaYNuVr0ysc18bfPjyU,929
322
324
  junifer/utils/tests/test_logging.py,sha256=W4tFKmaf8_CxnWZ-o_-XxM7DQbhGG18RsLZJk8bZelI,8163
323
- junifer-0.0.7.dev72.dist-info/licenses/AUTHORS.rst,sha256=rmULKpchpSol4ExWFdm-qu4fkpSZPYqIESVJBZtGb6E,163
324
- junifer-0.0.7.dev72.dist-info/licenses/LICENSE.md,sha256=MqCnOBu8uXsEOzRZWh9EBVfVz-kE9NkXcLCrtGXo2yU,34354
325
- junifer-0.0.7.dev72.dist-info/METADATA,sha256=VRpJuhWDpLEMFpJPke6QnTbLN-oOXRUbzoiUwr0LwlM,8387
326
- junifer-0.0.7.dev72.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
327
- junifer-0.0.7.dev72.dist-info/entry_points.txt,sha256=6O8ru0BP-SP7YMUZiizFNoaZ2HvJpadO2G7nKk4PwjI,48
328
- junifer-0.0.7.dev72.dist-info/top_level.txt,sha256=4bAq1R2QFQ4b3hohjys2JBvxrl0GKk5LNFzYvz9VGcA,8
329
- junifer-0.0.7.dev72.dist-info/RECORD,,
325
+ junifer-0.0.7.dev93.dist-info/licenses/AUTHORS.rst,sha256=rmULKpchpSol4ExWFdm-qu4fkpSZPYqIESVJBZtGb6E,163
326
+ junifer-0.0.7.dev93.dist-info/licenses/LICENSE.md,sha256=MqCnOBu8uXsEOzRZWh9EBVfVz-kE9NkXcLCrtGXo2yU,34354
327
+ junifer-0.0.7.dev93.dist-info/METADATA,sha256=XJDtsS1aolWYxCr-iCbrso20QFIP8bciZm9-BxskKWk,8387
328
+ junifer-0.0.7.dev93.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
329
+ junifer-0.0.7.dev93.dist-info/entry_points.txt,sha256=6O8ru0BP-SP7YMUZiizFNoaZ2HvJpadO2G7nKk4PwjI,48
330
+ junifer-0.0.7.dev93.dist-info/top_level.txt,sha256=4bAq1R2QFQ4b3hohjys2JBvxrl0GKk5LNFzYvz9VGcA,8
331
+ junifer-0.0.7.dev93.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.3.1)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5