junifer 0.0.3.dev186__py3-none-any.whl → 0.0.4__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.
Files changed (178) hide show
  1. junifer/_version.py +14 -2
  2. junifer/api/cli.py +162 -17
  3. junifer/api/functions.py +87 -419
  4. junifer/api/parser.py +24 -0
  5. junifer/api/queue_context/__init__.py +8 -0
  6. junifer/api/queue_context/gnu_parallel_local_adapter.py +258 -0
  7. junifer/api/queue_context/htcondor_adapter.py +365 -0
  8. junifer/api/queue_context/queue_context_adapter.py +60 -0
  9. junifer/api/queue_context/tests/test_gnu_parallel_local_adapter.py +192 -0
  10. junifer/api/queue_context/tests/test_htcondor_adapter.py +257 -0
  11. junifer/api/res/afni/run_afni_docker.sh +6 -6
  12. junifer/api/res/ants/ResampleImage +3 -0
  13. junifer/api/res/ants/antsApplyTransforms +3 -0
  14. junifer/api/res/ants/antsApplyTransformsToPoints +3 -0
  15. junifer/api/res/ants/run_ants_docker.sh +39 -0
  16. junifer/api/res/fsl/applywarp +3 -0
  17. junifer/api/res/fsl/flirt +3 -0
  18. junifer/api/res/fsl/img2imgcoord +3 -0
  19. junifer/api/res/fsl/run_fsl_docker.sh +39 -0
  20. junifer/api/res/fsl/std2imgcoord +3 -0
  21. junifer/api/res/run_conda.sh +4 -4
  22. junifer/api/res/run_venv.sh +22 -0
  23. junifer/api/tests/data/partly_cloudy_agg_mean_tian.yml +16 -0
  24. junifer/api/tests/test_api_utils.py +21 -3
  25. junifer/api/tests/test_cli.py +232 -9
  26. junifer/api/tests/test_functions.py +211 -439
  27. junifer/api/tests/test_parser.py +1 -1
  28. junifer/configs/juseless/datagrabbers/aomic_id1000_vbm.py +6 -1
  29. junifer/configs/juseless/datagrabbers/camcan_vbm.py +6 -1
  30. junifer/configs/juseless/datagrabbers/ixi_vbm.py +6 -1
  31. junifer/configs/juseless/datagrabbers/tests/test_ucla.py +8 -8
  32. junifer/configs/juseless/datagrabbers/ucla.py +44 -26
  33. junifer/configs/juseless/datagrabbers/ukb_vbm.py +6 -1
  34. junifer/data/VOIs/meta/AutobiographicalMemory_VOIs.txt +23 -0
  35. junifer/data/VOIs/meta/Power2013_MNI_VOIs.tsv +264 -0
  36. junifer/data/__init__.py +4 -0
  37. junifer/data/coordinates.py +298 -31
  38. junifer/data/masks.py +360 -28
  39. junifer/data/parcellations.py +621 -188
  40. junifer/data/template_spaces.py +190 -0
  41. junifer/data/tests/test_coordinates.py +34 -3
  42. junifer/data/tests/test_data_utils.py +1 -0
  43. junifer/data/tests/test_masks.py +202 -86
  44. junifer/data/tests/test_parcellations.py +266 -55
  45. junifer/data/tests/test_template_spaces.py +104 -0
  46. junifer/data/utils.py +4 -2
  47. junifer/datagrabber/__init__.py +1 -0
  48. junifer/datagrabber/aomic/id1000.py +111 -70
  49. junifer/datagrabber/aomic/piop1.py +116 -53
  50. junifer/datagrabber/aomic/piop2.py +116 -53
  51. junifer/datagrabber/aomic/tests/test_id1000.py +27 -27
  52. junifer/datagrabber/aomic/tests/test_piop1.py +27 -27
  53. junifer/datagrabber/aomic/tests/test_piop2.py +27 -27
  54. junifer/datagrabber/base.py +62 -10
  55. junifer/datagrabber/datalad_base.py +0 -2
  56. junifer/datagrabber/dmcc13_benchmark.py +372 -0
  57. junifer/datagrabber/hcp1200/datalad_hcp1200.py +5 -0
  58. junifer/datagrabber/hcp1200/hcp1200.py +30 -13
  59. junifer/datagrabber/pattern.py +133 -27
  60. junifer/datagrabber/pattern_datalad.py +111 -13
  61. junifer/datagrabber/tests/test_base.py +57 -6
  62. junifer/datagrabber/tests/test_datagrabber_utils.py +204 -76
  63. junifer/datagrabber/tests/test_datalad_base.py +0 -6
  64. junifer/datagrabber/tests/test_dmcc13_benchmark.py +256 -0
  65. junifer/datagrabber/tests/test_multiple.py +43 -10
  66. junifer/datagrabber/tests/test_pattern.py +125 -178
  67. junifer/datagrabber/tests/test_pattern_datalad.py +44 -25
  68. junifer/datagrabber/utils.py +151 -16
  69. junifer/datareader/default.py +36 -10
  70. junifer/external/nilearn/junifer_nifti_spheres_masker.py +6 -0
  71. junifer/markers/base.py +25 -16
  72. junifer/markers/collection.py +35 -16
  73. junifer/markers/complexity/__init__.py +27 -0
  74. junifer/markers/complexity/complexity_base.py +149 -0
  75. junifer/markers/complexity/hurst_exponent.py +136 -0
  76. junifer/markers/complexity/multiscale_entropy_auc.py +140 -0
  77. junifer/markers/complexity/perm_entropy.py +132 -0
  78. junifer/markers/complexity/range_entropy.py +136 -0
  79. junifer/markers/complexity/range_entropy_auc.py +145 -0
  80. junifer/markers/complexity/sample_entropy.py +134 -0
  81. junifer/markers/complexity/tests/test_complexity_base.py +19 -0
  82. junifer/markers/complexity/tests/test_hurst_exponent.py +69 -0
  83. junifer/markers/complexity/tests/test_multiscale_entropy_auc.py +68 -0
  84. junifer/markers/complexity/tests/test_perm_entropy.py +68 -0
  85. junifer/markers/complexity/tests/test_range_entropy.py +69 -0
  86. junifer/markers/complexity/tests/test_range_entropy_auc.py +69 -0
  87. junifer/markers/complexity/tests/test_sample_entropy.py +68 -0
  88. junifer/markers/complexity/tests/test_weighted_perm_entropy.py +68 -0
  89. junifer/markers/complexity/weighted_perm_entropy.py +133 -0
  90. junifer/markers/falff/_afni_falff.py +153 -0
  91. junifer/markers/falff/_junifer_falff.py +142 -0
  92. junifer/markers/falff/falff_base.py +91 -84
  93. junifer/markers/falff/falff_parcels.py +61 -45
  94. junifer/markers/falff/falff_spheres.py +64 -48
  95. junifer/markers/falff/tests/test_falff_parcels.py +89 -121
  96. junifer/markers/falff/tests/test_falff_spheres.py +92 -127
  97. junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py +1 -0
  98. junifer/markers/functional_connectivity/edge_functional_connectivity_parcels.py +1 -0
  99. junifer/markers/functional_connectivity/functional_connectivity_base.py +1 -0
  100. junifer/markers/functional_connectivity/tests/test_crossparcellation_functional_connectivity.py +46 -44
  101. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_parcels.py +34 -39
  102. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_spheres.py +40 -52
  103. junifer/markers/functional_connectivity/tests/test_functional_connectivity_parcels.py +62 -70
  104. junifer/markers/functional_connectivity/tests/test_functional_connectivity_spheres.py +99 -85
  105. junifer/markers/parcel_aggregation.py +60 -38
  106. junifer/markers/reho/_afni_reho.py +192 -0
  107. junifer/markers/reho/_junifer_reho.py +281 -0
  108. junifer/markers/reho/reho_base.py +69 -34
  109. junifer/markers/reho/reho_parcels.py +26 -16
  110. junifer/markers/reho/reho_spheres.py +23 -9
  111. junifer/markers/reho/tests/test_reho_parcels.py +93 -92
  112. junifer/markers/reho/tests/test_reho_spheres.py +88 -86
  113. junifer/markers/sphere_aggregation.py +54 -9
  114. junifer/markers/temporal_snr/temporal_snr_base.py +1 -0
  115. junifer/markers/temporal_snr/tests/test_temporal_snr_parcels.py +38 -37
  116. junifer/markers/temporal_snr/tests/test_temporal_snr_spheres.py +34 -38
  117. junifer/markers/tests/test_collection.py +43 -42
  118. junifer/markers/tests/test_ets_rss.py +29 -37
  119. junifer/markers/tests/test_parcel_aggregation.py +587 -468
  120. junifer/markers/tests/test_sphere_aggregation.py +209 -157
  121. junifer/markers/utils.py +2 -40
  122. junifer/onthefly/read_transform.py +13 -6
  123. junifer/pipeline/__init__.py +1 -0
  124. junifer/pipeline/pipeline_step_mixin.py +105 -41
  125. junifer/pipeline/registry.py +17 -0
  126. junifer/pipeline/singleton.py +45 -0
  127. junifer/pipeline/tests/test_pipeline_step_mixin.py +139 -51
  128. junifer/pipeline/tests/test_update_meta_mixin.py +1 -0
  129. junifer/pipeline/tests/test_workdir_manager.py +104 -0
  130. junifer/pipeline/update_meta_mixin.py +8 -2
  131. junifer/pipeline/utils.py +154 -15
  132. junifer/pipeline/workdir_manager.py +246 -0
  133. junifer/preprocess/__init__.py +3 -0
  134. junifer/preprocess/ants/__init__.py +4 -0
  135. junifer/preprocess/ants/ants_apply_transforms_warper.py +185 -0
  136. junifer/preprocess/ants/tests/test_ants_apply_transforms_warper.py +56 -0
  137. junifer/preprocess/base.py +96 -69
  138. junifer/preprocess/bold_warper.py +265 -0
  139. junifer/preprocess/confounds/fmriprep_confound_remover.py +91 -134
  140. junifer/preprocess/confounds/tests/test_fmriprep_confound_remover.py +106 -111
  141. junifer/preprocess/fsl/__init__.py +4 -0
  142. junifer/preprocess/fsl/apply_warper.py +179 -0
  143. junifer/preprocess/fsl/tests/test_apply_warper.py +45 -0
  144. junifer/preprocess/tests/test_bold_warper.py +159 -0
  145. junifer/preprocess/tests/test_preprocess_base.py +6 -6
  146. junifer/preprocess/warping/__init__.py +6 -0
  147. junifer/preprocess/warping/_ants_warper.py +167 -0
  148. junifer/preprocess/warping/_fsl_warper.py +109 -0
  149. junifer/preprocess/warping/space_warper.py +213 -0
  150. junifer/preprocess/warping/tests/test_space_warper.py +198 -0
  151. junifer/stats.py +18 -4
  152. junifer/storage/base.py +9 -1
  153. junifer/storage/hdf5.py +8 -3
  154. junifer/storage/pandas_base.py +2 -1
  155. junifer/storage/sqlite.py +1 -0
  156. junifer/storage/tests/test_hdf5.py +2 -1
  157. junifer/storage/tests/test_sqlite.py +8 -8
  158. junifer/storage/tests/test_utils.py +6 -6
  159. junifer/storage/utils.py +1 -0
  160. junifer/testing/datagrabbers.py +11 -7
  161. junifer/testing/utils.py +1 -0
  162. junifer/tests/test_stats.py +2 -0
  163. junifer/utils/__init__.py +1 -0
  164. junifer/utils/helpers.py +53 -0
  165. junifer/utils/logging.py +14 -3
  166. junifer/utils/tests/test_helpers.py +35 -0
  167. {junifer-0.0.3.dev186.dist-info → junifer-0.0.4.dist-info}/METADATA +59 -28
  168. junifer-0.0.4.dist-info/RECORD +257 -0
  169. {junifer-0.0.3.dev186.dist-info → junifer-0.0.4.dist-info}/WHEEL +1 -1
  170. junifer/markers/falff/falff_estimator.py +0 -334
  171. junifer/markers/falff/tests/test_falff_estimator.py +0 -238
  172. junifer/markers/reho/reho_estimator.py +0 -515
  173. junifer/markers/reho/tests/test_reho_estimator.py +0 -260
  174. junifer-0.0.3.dev186.dist-info/RECORD +0 -199
  175. {junifer-0.0.3.dev186.dist-info → junifer-0.0.4.dist-info}/AUTHORS.rst +0 -0
  176. {junifer-0.0.3.dev186.dist-info → junifer-0.0.4.dist-info}/LICENSE.md +0 -0
  177. {junifer-0.0.3.dev186.dist-info → junifer-0.0.4.dist-info}/entry_points.txt +0 -0
  178. {junifer-0.0.3.dev186.dist-info → junifer-0.0.4.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,190 @@
1
+ """Provide functions for template spaces."""
2
+
3
+ # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
+ # License: AGPL
5
+
6
+ from pathlib import Path
7
+ from typing import Any, Dict, Optional, Union
8
+
9
+ import httpx
10
+ import nibabel as nib
11
+ import numpy as np
12
+ from templateflow import api as tflow
13
+
14
+ from ..utils import logger, raise_error
15
+ from .utils import closest_resolution
16
+
17
+
18
+ def get_xfm(
19
+ src: str, dst: str, xfms_dir: Union[str, Path, None] = None
20
+ ) -> Path: # pragma: no cover
21
+ """Fetch warp files to convert from ``src`` to ``dst``.
22
+
23
+ Parameters
24
+ ----------
25
+ src : str
26
+ The template space to transform from.
27
+ dst : str
28
+ The template space to transform to.
29
+ xfms_dir : str or pathlib.Path, optional
30
+ Path where the retrieved transformation files are stored.
31
+ The default location is "$HOME/junifer/data/xfms" (default None).
32
+
33
+ Returns
34
+ -------
35
+ pathlib.Path
36
+ The path to the transformation file.
37
+
38
+ Raises
39
+ ------
40
+ RuntimeError
41
+ If there is a problem fetching files.
42
+
43
+ """
44
+ if xfms_dir is None:
45
+ xfms_dir = Path().home() / "junifer" / "data" / "xfms"
46
+ logger.debug(f"Creating xfm directory at: {xfms_dir.resolve()}")
47
+ # Create default junifer data directory if not present
48
+ xfms_dir.mkdir(exist_ok=True, parents=True)
49
+ # Convert str to Path
50
+ elif not isinstance(xfms_dir, Path):
51
+ xfms_dir = Path(xfms_dir)
52
+
53
+ # Set local file prefix
54
+ xfm_file_prefix = f"{src}_to_{dst}"
55
+ # Set local file dir
56
+ xfm_file_dir = xfms_dir / xfm_file_prefix
57
+ # Create local directory if not present
58
+ xfm_file_dir.mkdir(exist_ok=True, parents=True)
59
+ # Set file name with extension
60
+ xfm_file = f"{src}_to_{dst}_Composite.h5"
61
+ # Set local file path
62
+ xfm_file_path = xfm_file_dir / xfm_file
63
+ # Check if the file exists
64
+ if xfm_file_path.exists():
65
+ logger.info(
66
+ f"Found existing xfm file for {src} to {dst} at "
67
+ f"{xfm_file_path.resolve()}"
68
+ )
69
+ return xfm_file_path
70
+
71
+ # Set URL
72
+ url = (
73
+ "https://gin.g-node.org/juaml/human-template-xfms/raw/main/xfms/"
74
+ f"{xfm_file_prefix}/{xfm_file}"
75
+ )
76
+ # Create the file before proceeding
77
+ xfm_file_path.touch()
78
+
79
+ logger.info(f"Downloading xfm file for {src} to {dst} from {url}")
80
+ # Steam response
81
+ with httpx.stream("GET", url) as resp:
82
+ try:
83
+ resp.raise_for_status()
84
+ except httpx.HTTPError as exc:
85
+ raise_error(
86
+ f"Error response {exc.response.status_code} while "
87
+ f"requesting {exc.request.url!r}",
88
+ klass=RuntimeError,
89
+ )
90
+ else:
91
+ with open(xfm_file_path, "ab") as f:
92
+ for chunk in resp.iter_bytes():
93
+ f.write(chunk)
94
+
95
+ return xfm_file_path
96
+
97
+
98
+ def get_template(
99
+ space: str,
100
+ target_data: Dict[str, Any],
101
+ extra_input: Optional[Dict[str, Any]] = None,
102
+ template_type: str = "T1w",
103
+ ) -> nib.Nifti1Image:
104
+ """Get template for the space, tailored for the target image.
105
+
106
+ Parameters
107
+ ----------
108
+ space : str
109
+ The name of the template space.
110
+ target_data : dict
111
+ The corresponding item of the data object for which the template space
112
+ will be loaded.
113
+ extra_input : dict, optional
114
+ The other fields in the data object. Useful for accessing other data
115
+ types (default None).
116
+ template_type : {"T1w", "brain", "gm", "wm", "csf"}, optional
117
+ The template type to retrieve (default "T1w").
118
+
119
+ Returns
120
+ -------
121
+ Nifti1Image
122
+ The template image.
123
+
124
+ Raises
125
+ ------
126
+ ValueError
127
+ If ``space`` or ``template_type`` is invalid.
128
+ RuntimeError
129
+ If required template is not found.
130
+
131
+ """
132
+ # Check for invalid space; early check to raise proper error
133
+ if space not in tflow.templates():
134
+ raise_error(f"Unknown template space: {space}")
135
+
136
+ # Check for template type
137
+ if template_type not in ["T1w", "brain", "gm", "wm", "csf"]:
138
+ raise_error(f"Unknown template type: {template_type}")
139
+
140
+ # Get the min of the voxels sizes and use it as the resolution
141
+ target_img = target_data["data"]
142
+ resolution = np.min(target_img.header.get_zooms()[:3]).astype(int)
143
+
144
+ # Fetch available resolutions for the template
145
+ available_resolutions = [
146
+ int(min(val["zooms"]))
147
+ for val in tflow.get_metadata(space)["res"].values()
148
+ ]
149
+ # Use the closest resolution if desired resolution is not found
150
+ resolution = closest_resolution(resolution, available_resolutions)
151
+
152
+ logger.info(f"Downloading template {space} in resolution {resolution}")
153
+ # Retrieve template
154
+ try:
155
+ suffix = None
156
+ desc = None
157
+ label = None
158
+ if template_type == "T1w":
159
+ suffix = template_type
160
+ desc = None
161
+ label = None
162
+ elif template_type == "brain":
163
+ suffix = "mask"
164
+ desc = "brain"
165
+ label = None
166
+ elif template_type in ["gm", "wm", "csf"]:
167
+ suffix = "probseg"
168
+ desc = None
169
+ label = template_type.upper()
170
+ # Set kwargs for fetching
171
+ kwargs = {
172
+ "suffix": suffix,
173
+ "desc": desc,
174
+ "label": label,
175
+ }
176
+ template_path = tflow.get(
177
+ space,
178
+ raise_empty=True,
179
+ resolution=resolution,
180
+ extension="nii.gz",
181
+ **kwargs,
182
+ )
183
+ except Exception: # noqa: BLE001
184
+ raise_error(
185
+ f"Template {space} ({template_type}) with resolution {resolution} "
186
+ "not found",
187
+ klass=RuntimeError,
188
+ )
189
+ else:
190
+ return nib.load(template_path) # type: ignore
@@ -8,10 +8,13 @@ import pytest
8
8
  from numpy.testing import assert_array_equal
9
9
 
10
10
  from junifer.data.coordinates import (
11
+ get_coordinates,
11
12
  list_coordinates,
12
13
  load_coordinates,
13
14
  register_coordinates,
14
15
  )
16
+ from junifer.datareader import DefaultDataReader
17
+ from junifer.testing.datagrabbers import OasisVBMTestingDataGrabber
15
18
 
16
19
 
17
20
  def test_register_coordinates_built_in_check() -> None:
@@ -21,6 +24,7 @@ def test_register_coordinates_built_in_check() -> None:
21
24
  name="DMNBuckner",
22
25
  coordinates=np.zeros(2),
23
26
  voi_names=["1", "2"],
27
+ space="MNI",
24
28
  overwrite=True,
25
29
  )
26
30
 
@@ -31,6 +35,7 @@ def test_register_coordinates_overwrite() -> None:
31
35
  name="MyList",
32
36
  coordinates=np.zeros((2, 3)),
33
37
  voi_names=["roi1", "roi2"],
38
+ space="MNI",
34
39
  overwrite=True,
35
40
  )
36
41
  with pytest.raises(ValueError, match=r"already registered"):
@@ -38,27 +43,31 @@ def test_register_coordinates_overwrite() -> None:
38
43
  name="MyList",
39
44
  coordinates=np.ones((2, 3)),
40
45
  voi_names=["roi2", "roi3"],
46
+ space="MNI",
41
47
  )
42
48
 
43
49
  register_coordinates(
44
50
  name="MyList",
45
51
  coordinates=np.ones((2, 3)),
46
52
  voi_names=["roi2", "roi3"],
53
+ space="MNI",
47
54
  overwrite=True,
48
55
  )
49
56
 
50
- coord, names = load_coordinates("MyList")
57
+ coord, names, space = load_coordinates("MyList")
51
58
  assert_array_equal(coord, np.ones((2, 3)))
52
59
  assert names == ["roi2", "roi3"]
60
+ assert space == "MNI"
53
61
 
54
62
 
55
63
  def test_register_coordinates_valid_input() -> None:
56
64
  """Test coordinates registration check for valid input."""
57
- with pytest.raises(ValueError, match=r"numpy.ndarray"):
65
+ with pytest.raises(TypeError, match=r"numpy.ndarray"):
58
66
  register_coordinates(
59
67
  name="MyList",
60
68
  coordinates=[1, 2],
61
69
  voi_names=["roi1", "roi2"],
70
+ space="MNI",
62
71
  overwrite=True,
63
72
  )
64
73
  with pytest.raises(ValueError, match=r"2D array"):
@@ -66,6 +75,7 @@ def test_register_coordinates_valid_input() -> None:
66
75
  name="MyList",
67
76
  coordinates=np.zeros((2, 3, 4)),
68
77
  voi_names=["roi1", "roi2"],
78
+ space="MNI",
69
79
  overwrite=True,
70
80
  )
71
81
 
@@ -74,6 +84,7 @@ def test_register_coordinates_valid_input() -> None:
74
84
  name="MyList",
75
85
  coordinates=np.zeros((2, 4)),
76
86
  voi_names=["roi1", "roi2"],
87
+ space="MNI",
77
88
  overwrite=True,
78
89
  )
79
90
  with pytest.raises(ValueError, match=r"voi_names"):
@@ -81,6 +92,7 @@ def test_register_coordinates_valid_input() -> None:
81
92
  name="MyList",
82
93
  coordinates=np.zeros((2, 3)),
83
94
  voi_names=["roi1", "roi2", "roi3"],
95
+ space="MNI",
84
96
  overwrite=True,
85
97
  )
86
98
 
@@ -96,12 +108,31 @@ def test_list_coordinates() -> None:
96
108
 
97
109
  def test_load_coordinates() -> None:
98
110
  """Test loading coordinates from file."""
99
- coord, names = load_coordinates("DMNBuckner")
111
+ coord, names, space = load_coordinates("DMNBuckner")
100
112
  assert coord.shape == (6, 3) # type: ignore
101
113
  assert names == ["PCC", "MPFC", "lAG", "rAG", "lHF", "rHF"]
114
+ assert space == "MNI"
102
115
 
103
116
 
104
117
  def test_load_coordinates_nonexisting() -> None:
105
118
  """Test loading coordinates that not exist."""
106
119
  with pytest.raises(ValueError, match=r"not found"):
107
120
  load_coordinates("NonExisting")
121
+
122
+
123
+ def test_get_coordinates() -> None:
124
+ """Test tailored coordinates fetch."""
125
+ reader = DefaultDataReader()
126
+ with OasisVBMTestingDataGrabber() as dg:
127
+ element = dg["sub-01"]
128
+ element_data = reader.fit_transform(element)
129
+ vbm_gm = element_data["VBM_GM"]
130
+ # Get tailored coordinates
131
+ tailored_coords, tailored_labels = get_coordinates(
132
+ coords="DMNBuckner", target_data=vbm_gm
133
+ )
134
+ # Get raw coordinates
135
+ raw_coords, raw_labels, _ = load_coordinates("DMNBuckner")
136
+ # Both tailored and raw should be same for now
137
+ assert_array_equal(tailored_coords, raw_coords)
138
+ assert tailored_labels == raw_labels
@@ -36,6 +36,7 @@ def test_closest_resolution(
36
36
  The valid resolutions.
37
37
  expected: float
38
38
  The expected result.
39
+
39
40
  """
40
41
  assert closest_resolution(resolution, valid_resolutions) == expected
41
42
  assert (