clabtoolkit 0.1.0__tar.gz → 0.3.0__tar.gz

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 (44) hide show
  1. clabtoolkit-0.3.0/HISTORY.rst +8 -0
  2. {clabtoolkit-0.1.0 → clabtoolkit-0.3.0}/PKG-INFO +3 -3
  3. {clabtoolkit-0.1.0 → clabtoolkit-0.3.0}/clabtoolkit/__init__.py +1 -1
  4. clabtoolkit-0.3.0/clabtoolkit/bidstools.py +590 -0
  5. clabtoolkit-0.3.0/clabtoolkit/dicomtools.py +560 -0
  6. {clabtoolkit-0.1.0 → clabtoolkit-0.3.0}/clabtoolkit/dwitools.py +1 -1
  7. clabtoolkit-0.3.0/clabtoolkit/freesurfertools.py +1847 -0
  8. clabtoolkit-0.3.0/clabtoolkit/imagetools.py +449 -0
  9. clabtoolkit-0.3.0/clabtoolkit/misctools.py +963 -0
  10. clabtoolkit-0.3.0/clabtoolkit/parcellationtools.py +1487 -0
  11. clabtoolkit-0.3.0/clabtoolkit/segmentationtools.py +336 -0
  12. clabtoolkit-0.3.0/clabtoolkit/surfacetools.py +92 -0
  13. {clabtoolkit-0.1.0 → clabtoolkit-0.3.0}/clabtoolkit.egg-info/PKG-INFO +3 -3
  14. {clabtoolkit-0.1.0 → clabtoolkit-0.3.0}/clabtoolkit.egg-info/SOURCES.txt +2 -0
  15. {clabtoolkit-0.1.0 → clabtoolkit-0.3.0}/setup.cfg +1 -1
  16. {clabtoolkit-0.1.0 → clabtoolkit-0.3.0}/setup.py +1 -1
  17. clabtoolkit-0.1.0/HISTORY.rst +0 -8
  18. clabtoolkit-0.1.0/clabtoolkit/bidstools.py +0 -156
  19. clabtoolkit-0.1.0/clabtoolkit/dicomtools.py +0 -161
  20. clabtoolkit-0.1.0/clabtoolkit/freesurfertools.py +0 -518
  21. clabtoolkit-0.1.0/clabtoolkit/misctools.py +0 -72
  22. clabtoolkit-0.1.0/clabtoolkit/parcellationtools.py +0 -89
  23. clabtoolkit-0.1.0/clabtoolkit/surfacetools.py +0 -0
  24. {clabtoolkit-0.1.0 → clabtoolkit-0.3.0}/AUTHORS.rst +0 -0
  25. {clabtoolkit-0.1.0 → clabtoolkit-0.3.0}/CONTRIBUTING.rst +0 -0
  26. {clabtoolkit-0.1.0 → clabtoolkit-0.3.0}/LICENSE +0 -0
  27. {clabtoolkit-0.1.0 → clabtoolkit-0.3.0}/MANIFEST.in +0 -0
  28. {clabtoolkit-0.1.0 → clabtoolkit-0.3.0}/README.rst +0 -0
  29. {clabtoolkit-0.1.0 → clabtoolkit-0.3.0}/clabtoolkit/examples.py +0 -0
  30. {clabtoolkit-0.1.0 → clabtoolkit-0.3.0}/clabtoolkit.egg-info/dependency_links.txt +0 -0
  31. {clabtoolkit-0.1.0 → clabtoolkit-0.3.0}/clabtoolkit.egg-info/not-zip-safe +0 -0
  32. {clabtoolkit-0.1.0 → clabtoolkit-0.3.0}/clabtoolkit.egg-info/top_level.txt +0 -0
  33. {clabtoolkit-0.1.0 → clabtoolkit-0.3.0}/docs/Makefile +0 -0
  34. {clabtoolkit-0.1.0 → clabtoolkit-0.3.0}/docs/authors.rst +0 -0
  35. {clabtoolkit-0.1.0 → clabtoolkit-0.3.0}/docs/conf.py +0 -0
  36. {clabtoolkit-0.1.0 → clabtoolkit-0.3.0}/docs/contributing.rst +0 -0
  37. {clabtoolkit-0.1.0 → clabtoolkit-0.3.0}/docs/history.rst +0 -0
  38. {clabtoolkit-0.1.0 → clabtoolkit-0.3.0}/docs/index.rst +0 -0
  39. {clabtoolkit-0.1.0 → clabtoolkit-0.3.0}/docs/installation.rst +0 -0
  40. {clabtoolkit-0.1.0 → clabtoolkit-0.3.0}/docs/make.bat +0 -0
  41. {clabtoolkit-0.1.0 → clabtoolkit-0.3.0}/docs/readme.rst +0 -0
  42. {clabtoolkit-0.1.0 → clabtoolkit-0.3.0}/docs/usage.rst +0 -0
  43. {clabtoolkit-0.1.0 → clabtoolkit-0.3.0}/tests/__init__.py +0 -0
  44. {clabtoolkit-0.1.0 → clabtoolkit-0.3.0}/tests/test_clabtoolkit.py +0 -0
@@ -0,0 +1,8 @@
1
+ =======
2
+ History
3
+ =======
4
+
5
+ 0.3.0 (2024-05-25)
6
+ ------------------
7
+
8
+ * Third release on PyPI.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: clabtoolkit
3
- Version: 0.1.0
3
+ Version: 0.3.0
4
4
  Summary: This package contains a set of useful tools for image processing
5
5
  Home-page: https://github.com/connectomicslab/clabtoolkit
6
6
  Author: Yasser Alemán-Gómez
@@ -62,7 +62,7 @@ This package was created with Cookiecutter_ and the `audreyr/cookiecutter-pypack
62
62
  History
63
63
  =======
64
64
 
65
- 0.0.3 (2024-03-07)
65
+ 0.3.0 (2024-05-25)
66
66
  ------------------
67
67
 
68
- * First stable release on PyPI.
68
+ * Third release on PyPI.
@@ -2,4 +2,4 @@
2
2
 
3
3
  __author__ = """Yasser Alemán-Gómez"""
4
4
  __email__ = "yasseraleman@protonmail.com"
5
- __version__ = "0.1.0"
5
+ __version__ = "0.2.0"
@@ -0,0 +1,590 @@
1
+ import os
2
+ import shutil
3
+ import pandas as pd
4
+ import clabtoolkit.misctools as cltmisc
5
+ from typing import Union, Dict, List
6
+
7
+
8
+ ####################################################################################################
9
+ ####################################################################################################
10
+ ############ ############
11
+ ############ ############
12
+ ############ Methods dedicated to work with BIDs naming conventions ############
13
+ ############ ############
14
+ ############ ############
15
+ ####################################################################################################
16
+ ####################################################################################################
17
+ def str2entity(string: str) -> dict:
18
+ """
19
+ Converts a formatted string into a dictionary.
20
+
21
+ Parameters
22
+ ----------
23
+ string : str
24
+ String to convert, with the format `key1-value1_key2-value2...suffix.extension`.
25
+
26
+ Returns
27
+ -------
28
+ dict
29
+ Dictionary containing the entities extracted from the string.
30
+
31
+ Examples
32
+ --------
33
+ >>> str2entity("sub-01_ses-M00_acq-3T_dir-AP_run-01_T1w.nii.gz")
34
+ Returns: {'sub': '01', 'ses': 'M00', 'acq': '3T', 'dir': 'AP', 'run': '01', 'suffix': 'T1w', 'extension': 'nii.gz'}
35
+
36
+ """
37
+ ent_dict = {}
38
+ suffix, extension = "", ""
39
+
40
+ # Split the string into entities based on underscores.
41
+ ent_list = string.split("_")
42
+
43
+ # Detect suffix and extension
44
+ for ent in ent_list[:]:
45
+ if "-" not in ent:
46
+ # If entity does not contain a '-', it's a suffix or extension.
47
+ if "." in ent:
48
+ # Split suffix and extension parts
49
+ suffix, extension = ent.split(".", 1)
50
+ else:
51
+ suffix = ent
52
+ ent_list.remove(ent)
53
+
54
+ # Process the remaining entities
55
+ for ent in ent_list:
56
+ key, value = ent.split("-", 1) # Split each entity on the first "-"
57
+ ent_dict[key] = value
58
+
59
+ # Add suffix and extension to the dictionary if they were found
60
+ if suffix:
61
+ ent_dict["suffix"] = suffix
62
+ if extension:
63
+ ent_dict["extension"] = extension
64
+
65
+ return ent_dict
66
+
67
+ ####################################################################################################
68
+ def entity2str(entity: dict) -> str:
69
+ """
70
+ Converts an entity dictionary to a string representation.
71
+
72
+ Parameters
73
+ ----------
74
+ entity : dict
75
+ Dictionary containing the entities.
76
+
77
+ Returns
78
+ -------
79
+ str
80
+ String containing the entities in the format `key1-value1_key2-value2...suffix.extension`.
81
+
82
+ Examples
83
+ --------
84
+ >>> entity2str({'sub': '01', 'ses': 'M00', 'acq': '3T', 'dir': 'AP', 'run': '01', 'suffix': 'T1w', 'extension': 'nii.gz'})
85
+ Returns: "sub-01_ses-M00_acq-3T_dir-AP_run-01_T1w.nii.gz"
86
+
87
+ """
88
+ # Make a copy of the entity dictionary to avoid mutating the original.
89
+ entity = entity.copy()
90
+
91
+ # Extract optional 'suffix' and 'extension' fields if present.
92
+ suffix = entity.pop("suffix", "")
93
+ extension = entity.pop("extension", "")
94
+
95
+ # Construct the main part of the string by joining key-value pairs with '_'
96
+ ent_string = "_".join(f"{key}-{str(value)}" for key, value in entity.items())
97
+
98
+ # Append suffix if it exists
99
+ if suffix:
100
+ ent_string += '_' + suffix
101
+ else:
102
+ ent_string = ent_string.rstrip("_") # Remove trailing underscore if no suffix
103
+
104
+ # Append extension if it exists
105
+ if extension:
106
+ ent_string += f".{extension}"
107
+
108
+ return ent_string
109
+
110
+ ####################################################################################################
111
+ def delete_entity(entity: Union[dict, str],
112
+ key2rem: Union[List[str], str]) -> Union[dict, str]:
113
+ """
114
+ Removes specified keys from an entity dictionary or string representation.
115
+
116
+ Parameters
117
+ ----------
118
+ entity : dict or str
119
+ Dictionary or string containing the entities.
120
+ key2rem : list or str
121
+ Key(s) to remove from the entity dictionary or string.
122
+
123
+ Returns
124
+ -------
125
+ Union[dict, str]
126
+ The updated entity as a dictionary or string (matching the input type).
127
+
128
+ Examples
129
+ --------
130
+ >>> delete_entity("sub-01_ses-M00_acq-3T_dir-AP_run-01_T1w.nii.gz", "acq")
131
+ Returns: "sub-01_ses-M00_dir-AP_run-01_T1w.nii.gz"
132
+
133
+ """
134
+ # Determine if `entity` is a string and convert if necessary.
135
+ is_string = isinstance(entity, str)
136
+ if is_string:
137
+ entity_out = str2entity(entity)
138
+ elif isinstance(entity, dict):
139
+ entity_out = entity.copy()
140
+ else:
141
+ raise ValueError("The entity must be a dictionary or a string.")
142
+
143
+ # Ensure `key2rem` is a list for uniform processing.
144
+ if isinstance(key2rem, str):
145
+ key2rem = [key2rem]
146
+
147
+ # Remove specified keys from the entity dictionary.
148
+ for key in key2rem:
149
+ entity_out.pop(key, None) # `pop` with default `None` avoids KeyErrors.
150
+
151
+ # Convert back to string format if original input was a string.
152
+ if is_string:
153
+ return entity2str(entity_out)
154
+
155
+ return entity_out
156
+
157
+ ####################################################################################################
158
+ def replace_entity_value(entity: Union[dict, str],
159
+ ent2replace: dict,
160
+ verbose: bool = False) -> Union[dict, str]:
161
+ """
162
+ Replaces values in an entity dictionary or string representation.
163
+
164
+ Parameters
165
+ ----------
166
+ entity : dict or str
167
+ Dictionary or string containing the entities.
168
+
169
+ ent2replace : dict
170
+ Dictionary of entities to replace with new values.
171
+
172
+ verbose : bool, optional
173
+ If True, prints warnings for non-existent or empty values.
174
+
175
+ Returns
176
+ -------
177
+ Union[dict, str]
178
+ Updated entity as a dictionary or string (matching the input type).
179
+
180
+ Examples
181
+ --------
182
+ >>> replace_entity_value("sub-01_ses-M00_acq-3T_dir-AP_run-01_T1w.nii.gz", {"acq": "7T"})
183
+ Returns: "sub-01_ses-M00_acq-7T_dir-AP_run-01_T1w.nii.gz"
184
+
185
+ """
186
+ # Determine if `entity` is a string and convert if necessary.
187
+ is_string = isinstance(entity, str)
188
+ if is_string:
189
+ entity_out = str2entity(entity)
190
+ elif isinstance(entity, dict):
191
+ entity_out = entity.copy()
192
+ else:
193
+ raise ValueError("The entity must be a dictionary or a string.")
194
+
195
+ # Remove any empty keys or values from `ent2replace`.
196
+ ent2replace = {k: v for k, v in ent2replace.items() if v}
197
+
198
+ # Replace values in `entity_out` based on `ent2replace`.
199
+ for key, new_value in ent2replace.items():
200
+ if key in entity_out:
201
+ if new_value:
202
+ entity_out[key] = new_value
203
+ elif verbose:
204
+ print(f"Warning: Replacement value for '{key}' is empty.")
205
+ elif verbose:
206
+ print(f"Warning: Entity '{key}' not found in entity dictionary.")
207
+
208
+ # Convert back to string format if original input was a string.
209
+ if is_string:
210
+ return entity2str(entity_out)
211
+
212
+ return entity_out
213
+
214
+ ####################################################################################################
215
+ def replace_entity_key(entity: Union[dict, str],
216
+ keys2replace: Dict[str, str],
217
+ verbose: bool = False) -> Union[dict, str]:
218
+ """
219
+ Replaces specified keys in an entity dictionary or string representation.
220
+
221
+ Parameters
222
+ ----------
223
+ entity : dict or str
224
+ Dictionary containing the entities or a string that follows the BIDS naming specifications.
225
+
226
+ keys2replace : dict
227
+ Dictionary mapping old keys to new keys.
228
+
229
+ verbose : bool, optional
230
+ If True, prints warnings for keys in `keys2replace` that are not found in `entity`.
231
+
232
+ Returns
233
+ -------
234
+ Union[dict, str]
235
+ Updated entity as a dictionary or string (matching the input type).
236
+
237
+ Examples
238
+ --------
239
+ >>> replace_entity_key("sub-01_ses-M00_acq-3T_dir-AP_run-01_T1w.nii.gz", {"acq": "TESTrep1", "dir": "TESTrep2"})
240
+ Returns: "sub-01_ses-M00_TESTrep1-3T_TESTrep2-AP_run-01_T1w.nii.gz"
241
+
242
+ """
243
+ # Convert `entity` to a dictionary if it's a string
244
+ is_string = isinstance(entity, str)
245
+ if is_string:
246
+ entity = str2entity(entity)
247
+ elif not isinstance(entity, dict):
248
+ raise ValueError("The entity must be a dictionary or a string.")
249
+
250
+ # Validate that `keys2replace` is a dictionary
251
+ if not isinstance(keys2replace, dict):
252
+ raise ValueError("The keys2replace parameter must be a dictionary.")
253
+
254
+ # Filter out any empty keys or values from `keys2replace`
255
+ keys2replace = {k: v for k, v in keys2replace.items() if k and v}
256
+
257
+ # Replace key names in the entity
258
+ entity_out = {}
259
+ for key, value in entity.items():
260
+ # Use the new key if it exists in `keys2replace`, otherwise keep the original key
261
+ new_key = keys2replace.get(key, key)
262
+ entity_out[new_key] = value
263
+
264
+ # Verbose output if the key to replace does not exist in the entity
265
+ if verbose and key in keys2replace and key not in entity:
266
+ print(f"Warning: Key '{key}' not found in the original dictionary.")
267
+
268
+ # Convert back to string format if the original input was a string
269
+ if is_string:
270
+ return entity2str(entity_out)
271
+
272
+ return entity_out
273
+
274
+ ####################################################################################################
275
+ def insert_entity(entity: Union[dict, str],
276
+ entity2add: Dict[str, str],
277
+ prev_entity: str = None) -> Union[dict, str]:
278
+ """
279
+ Adds entities to an existing entity dictionary or string representation.
280
+
281
+ Parameters
282
+ ----------
283
+ entity : dict or str
284
+ Dictionary containing the entities or a string that follows the BIDS naming specifications.
285
+
286
+ entity2add : dict
287
+ Dictionary containing the entities to add.
288
+
289
+ prev_entity : str, optional
290
+ Key in `entity` after which to insert the new entities.
291
+
292
+ Returns
293
+ -------
294
+ Union[dict, str]
295
+ Updated entity with the new entities added (matching the input type).
296
+
297
+ Examples
298
+ --------
299
+ >>> insert_entity("sub-01_ses-M00_acq-3T_dir-AP_run-01_T1w.nii.gz", {"task": "rest"})
300
+ Returns: "sub-01_ses-M00_acq-3T_dir-AP_run-01_task-rest_T1w.nii.gz"
301
+
302
+ >>> insert_entity("sub-01_ses-M00_acq-3T_dir-AP_run-01_T1w.nii.gz", {"task": "rest"}, prev_entity="ses")
303
+ Returns: "sub-01_ses-M00_task-rest_acq-3T_dir-AP_run-01_T1w.nii.gz"
304
+
305
+ """
306
+
307
+ # Determine if `entity` is a string and convert if necessary
308
+ is_string = isinstance(entity, str)
309
+ if is_string:
310
+ entity = str2entity(entity)
311
+ elif not isinstance(entity, dict):
312
+ raise ValueError("The entity must be a dictionary or a string.")
313
+
314
+ # Clean `entity2add` by removing any empty keys or values
315
+ entity2add = {k: v for k, v in entity2add.items() if k and v}
316
+
317
+ # Validate `prev_entity` if provided
318
+ if prev_entity is not None and prev_entity not in entity:
319
+ raise ValueError(f"Reference entity '{prev_entity}' is not in the entity dictionary.")
320
+
321
+ # Temporarily remove `suffix` and `extension` if they exist
322
+ suffix = entity.pop("suffix", None)
323
+ extension = entity.pop("extension", None)
324
+
325
+ # Build `ent_out` by adding items from `entity`, and insert `entity2add` after `prev_entity` if specified
326
+ ent_out = {}
327
+ for key, value in entity.items():
328
+ ent_out[key] = value
329
+ if key == prev_entity:
330
+ ent_out.update(entity2add) # Insert new entities immediately after `prev_entity`
331
+
332
+ # If no `prev_entity` is specified or if `prev_entity` is "suffix", append `entity2add` at the end
333
+ if prev_entity is None or prev_entity == "suffix":
334
+ ent_out.update(entity2add)
335
+
336
+ # Restore `suffix` and `extension` if they were removed
337
+ if suffix:
338
+ ent_out["suffix"] = suffix
339
+ if extension:
340
+ ent_out["extension"] = extension
341
+
342
+ # Convert back to string format if the original input was a string
343
+ if is_string:
344
+ return entity2str(ent_out)
345
+
346
+ return ent_out
347
+
348
+ ####################################################################################################
349
+ def recursively_replace_entity_value(root_dir:str,
350
+ dict2old: Union[dict, str],
351
+ dict2new: Union[dict, str]):
352
+
353
+ """
354
+ This method replaces the values of certain entities in all the files and folders of a BIDs dataset.
355
+
356
+ Parameters:
357
+ ----------
358
+ root_dir: str
359
+ Root directory of the BIDs dataset
360
+
361
+ dict2old: dict or str
362
+ Dictionary containing the entities to replace and their old values
363
+
364
+ dict2new: dict or str
365
+ Dictionary containing the entities to replace and their new values
366
+
367
+
368
+ """
369
+
370
+ # Detect if the BIDs directory exists
371
+ if not os.path.isdir(root_dir):
372
+ raise ValueError("The BIDs directory does not exist.")
373
+
374
+ # Convert the strings to dictionaries
375
+ if isinstance(dict2old, str):
376
+ dict2old = str2entity(dict2old)
377
+ if isinstance(dict2new, str):
378
+ dict2new = str2entity(dict2new)
379
+
380
+
381
+ # Leave in the dictionaries only the keys that are common
382
+ dict2old = {k: dict2old[k] for k in dict2old if k in dict2new}
383
+ dict2new = {k: dict2new[k] for k in dict2new if k in dict2old}
384
+
385
+ # Order the dictionaries alphabetically by key
386
+ dict2old = dict(sorted(dict2old.items()))
387
+ dict2new = dict(sorted(dict2new.items()))
388
+
389
+ # Creating the list of strings
390
+ dict2old_list = [f"{key}-{value}" for key, value in dict2old.items()]
391
+ dict2new_list = [f"{key}-{value}" for key, value in dict2new.items()]
392
+
393
+ # Find all the files and folders that contain a certain string any of the key values in the dictionary dict2old
394
+
395
+ # Walk through the directory from bottom to top (reverse)
396
+ for root, dirs, files in os.walk(root_dir, topdown=False):
397
+ # Rename files
398
+ for file_name in files:
399
+
400
+ for i, subst_x in enumerate(dict2old_list):
401
+ subst_y = dict2new_list[i]
402
+ if subst_x in file_name:
403
+ old_path = os.path.join(root, file_name)
404
+ new_name = file_name.replace(subst_x, subst_y)
405
+ new_path = os.path.join(root, new_name)
406
+ os.rename(old_path, new_path)
407
+ file_name = new_name
408
+
409
+ # the file is the tsv open the file and replace the string
410
+ if file_name.endswith('sessions.tsv'):
411
+ tsv_file = os.path.join(root,file_name)
412
+ # Read line by line and replace the string
413
+ # Load the TSV file
414
+ df = pd.read_csv(tsv_file, sep='\t')
415
+
416
+ # Replace subst_x with subst_y in all string columns
417
+ df = df.applymap(lambda x: x.replace(subst_x, subst_y) if isinstance(x, str) else x)
418
+
419
+ # Save the modified DataFrame as a TSV file
420
+ df.to_csv(tsv_file, sep='\t', index=False)
421
+
422
+ # Rename directories
423
+ for dir_name in dirs:
424
+ if subst_x in dir_name:
425
+ old_path = os.path.join(root, dir_name)
426
+ new_name = dir_name.replace(subst_x, subst_y)
427
+ new_path = os.path.join(root, new_name)
428
+ os.rename(old_path, new_path)
429
+
430
+ ####################################################################################################
431
+ ####################################################################################################
432
+ ############ ############
433
+ ############ ############
434
+ ############ Methods dedicated to work with BIDs file organization ############
435
+ ############ ############
436
+ ############ ############
437
+ ####################################################################################################
438
+ ####################################################################################################
439
+
440
+ # This function copies the BIDs folder and its derivatives for e given subjects to a new location
441
+ def copy_bids_folder(
442
+ bids_dir: str,
443
+ out_dir: str,
444
+ fold2copy: list = ["anat"],
445
+ subjs2copy: str = None,
446
+ deriv_dir: str = None,
447
+ include_derivatives: bool = False,
448
+ ):
449
+ """
450
+ Copy full bids folders
451
+ @params:
452
+ bids_dir - Required : BIDs dataset directory:
453
+ out_dir - Required : Output directory:
454
+ fold2copy - Optional : List of folders to copy: default = ['anat']
455
+ subjs2copy - Optional : List of subjects to copy:
456
+ deriv_dir - Optional : Derivatives directory: default = None
457
+ include_derivatives - Optional : Include derivatives folder: default = False
458
+ """
459
+
460
+ # Listing the subject ids inside the dicom folder
461
+ if subjs2copy is None:
462
+ my_list = os.listdir(bids_dir)
463
+ subj_ids = []
464
+ for it in my_list:
465
+ if "sub-" in it:
466
+ subj_ids.append(it)
467
+ subj_ids.sort()
468
+ else:
469
+ subj_ids = subjs2copy
470
+
471
+ # Selecting the derivatives folder
472
+ if include_derivatives:
473
+ if deriv_dir is None:
474
+ deriv_dir = os.path.join(bids_dir, "derivatives")
475
+
476
+ if not os.path.isdir(deriv_dir):
477
+ # Lunch a warning message if the derivatives folder does not exist
478
+ print("WARNING: The derivatives folder does not exist.")
479
+ print("WARNING: The derivatives folder will not be copied.")
480
+ include_derivatives = False
481
+
482
+ # Selecting all the derivatives folders
483
+ der_pipe_folders = []
484
+ directories = os.listdir(deriv_dir)
485
+ der_pipe_folders = []
486
+ for directory in directories:
487
+ pipe_dir = os.path.join(deriv_dir, directory)
488
+ if not directory.startswith(".") and os.path.isdir(pipe_dir):
489
+ der_pipe_folders.append(pipe_dir)
490
+
491
+ # Failed sessions and derivatives
492
+ fail_sess = []
493
+ fail_deriv = []
494
+
495
+ # Loop around all the subjects
496
+ nsubj = len(subj_ids)
497
+ for i, subj_id in enumerate(subj_ids): # Loop along the IDs
498
+ subj_dir = os.path.join(bids_dir, subj_id)
499
+ out_subj_dir = os.path.join(out_dir, subj_id)
500
+
501
+ cltmisc.printprogressbar(
502
+ i + 1,
503
+ nsubj,
504
+ "Processing subject "
505
+ + subj_id
506
+ + ": "
507
+ + "("
508
+ + str(i + 1)
509
+ + "/"
510
+ + str(nsubj)
511
+ + ")",
512
+ )
513
+
514
+ # Loop along all the sessions inside the subject directory
515
+ for ses_id in os.listdir(subj_dir): # Loop along the session
516
+ ses_dir = os.path.join(subj_dir, ses_id)
517
+ out_ses_dir = os.path.join(out_subj_dir, ses_id)
518
+
519
+ # print('Copying SubjectId: ' + subjId + ' ======> Session: ' + sesId)
520
+
521
+ if fold2copy[0] == "all":
522
+ directories = os.listdir(ses_dir)
523
+ fold2copy = []
524
+ for directory in directories:
525
+ if not directory.startswith(".") and os.path.isdir(
526
+ os.path.join(ses_dir, directory)
527
+ ):
528
+ print(directory)
529
+ fold2copy.append(directory)
530
+
531
+ for fc in fold2copy:
532
+ # Copying the anat folder
533
+ if os.path.isdir(ses_dir):
534
+ fold_to_copy = os.path.join(ses_dir, fc)
535
+
536
+ try:
537
+ # Creating destination directory using make directory
538
+ dest_dir = os.path.join(out_ses_dir, fc)
539
+ os.makedirs(dest_dir, exist_ok=True)
540
+
541
+ shutil.copytree(fold_to_copy, dest_dir, dirs_exist_ok=True)
542
+
543
+ except:
544
+ fail_sess.append(fold_to_copy)
545
+
546
+ if include_derivatives:
547
+ # Copying the derivatives folder
548
+
549
+ for pipe_dir in der_pipe_folders:
550
+ if os.path.isdir(pipe_dir):
551
+
552
+ out_pipe_dir = os.path.join(
553
+ out_dir, "derivatives", os.path.basename(pipe_dir)
554
+ )
555
+
556
+ pipe_indiv_subj_in = os.path.join(pipe_dir, subj_id, ses_id)
557
+ pipe_indiv_subj_out = os.path.join(
558
+ out_pipe_dir, subj_id, ses_id
559
+ )
560
+
561
+ if os.path.isdir(pipe_indiv_subj_in):
562
+ try:
563
+ # Creating destination directory using make directory
564
+ os.makedirs(pipe_indiv_subj_out, exist_ok=True)
565
+
566
+ # Copying the folder
567
+ shutil.copytree(
568
+ pipe_indiv_subj_in,
569
+ pipe_indiv_subj_out,
570
+ dirs_exist_ok=True,
571
+ )
572
+
573
+ except:
574
+ fail_deriv.append(pipe_indiv_subj_in)
575
+
576
+ # Print the failed sessions and derivatives
577
+ print(" ")
578
+ if fail_sess:
579
+ print("THE PROCESS FAILED COPYING THE FOLLOWING SESSIONS:")
580
+ for i in fail_sess:
581
+ print(i)
582
+ print(" ")
583
+
584
+ if fail_deriv:
585
+ print("THE PROCESS FAILED COPYING THE FOLLOWING DERIVATIVES:")
586
+ for i in fail_deriv:
587
+ print(i)
588
+ print(" ")
589
+
590
+ print("End of copying the files.")