1- '''Module to import Nipype Pipeline engine and override some Classes.
2- See https://fcp-indi.github.io/docs/developer/nodes
3- for C-PAC-specific documentation.
4- See https://nipype.readthedocs.io/en/latest/api/generated/nipype.pipeline.engine.html
5- for Nipype's documentation.
1+ # STATEMENT OF CHANGES:
2+ # This file is derived from sources licensed under the Apache-2.0 terms,
3+ # and this file has been changed.
64
7- STATEMENT OF CHANGES:
8- This file is derived from sources licensed under the Apache-2.0 terms,
9- and this file has been changed.
5+ # CHANGES:
6+ # * Supports just-in-time dynamic memory allocation
7+ # * Skips doctests that require files that we haven't copied over
8+ # * Applies a random seed
9+ # * Supports overriding memory estimates via a log file and a buffer
10+ # * Adds quotation marks around strings in dotfiles
1011
11- CHANGES:
12- * Supports just-in-time dynamic memory allocation
13- * Skips doctests that require files that we haven't copied over
14- * Applies a random seed
15- * Supports overriding memory estimates via a log file and a buffer
12+ # ORIGINAL WORK'S ATTRIBUTION NOTICE:
13+ # Copyright (c) 2009-2016, Nipype developers
1614
17- ORIGINAL WORK'S ATTRIBUTION NOTICE:
18- Copyright (c) 2009-2016, Nipype developers
15+ # Licensed under the Apache License, Version 2.0 (the "License");
16+ # you may not use this file except in compliance with the License.
17+ # You may obtain a copy of the License at
1918
20- Licensed under the Apache License, Version 2.0 (the "License");
21- you may not use this file except in compliance with the License.
22- You may obtain a copy of the License at
19+ # http://www.apache.org/licenses/LICENSE-2.0
2320
24- http://www.apache.org/licenses/LICENSE-2.0
21+ # Unless required by applicable law or agreed to in writing, software
22+ # distributed under the License is distributed on an "AS IS" BASIS,
23+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24+ # See the License for the specific language governing permissions and
25+ # limitations under the License.
2526
26- Unless required by applicable law or agreed to in writing, software
27- distributed under the License is distributed on an "AS IS" BASIS,
28- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29- See the License for the specific language governing permissions and
30- limitations under the License.
27+ # Prior to release 0.12, Nipype was licensed under a BSD license.
3128
32- Prior to release 0.12, Nipype was licensed under a BSD license.
29+ # Modifications Copyright (C) 2022 C-PAC Developers
3330
34- Modifications Copyright (C) 2022 C-PAC Developers
31+ # This file is part of C-PAC.
3532
36- This file is part of C-PAC.''' # noqa: E501
33+ # C-PAC is free software: you can redistribute it and/or modify it under
34+ # the terms of the GNU Lesser General Public License as published by the
35+ # Free Software Foundation, either version 3 of the License, or (at your
36+ # option) any later version.
37+
38+ # C-PAC is distributed in the hope that it will be useful, but WITHOUT
39+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
40+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
41+ # License for more details.
42+
43+ # You should have received a copy of the GNU Lesser General Public
44+ # License along with C-PAC. If not, see <https://www.gnu.org/licenses/>.
45+ '''Module to import Nipype Pipeline engine and override some Classes.
46+ See https://fcp-indi.github.io/docs/developer/nodes
47+ for C-PAC-specific documentation.
48+ See https://nipype.readthedocs.io/en/latest/api/generated/nipype.pipeline.engine.html
49+ for Nipype's documentation.''' # noqa: E501 # pylint: disable=line-too-long
3750import os
3851import re
39- from logging import getLogger
4052from inspect import Parameter , Signature , signature
53+ from logging import getLogger
54+ from typing import Iterable , Tuple , Union
4155from nibabel import load
4256from nipype import logging
4357from nipype .interfaces .utility import Function
5367UNDEFINED_SIZE = (42 , 42 , 42 , 1200 )
5468
5569random_state_logger = getLogger ('random' )
70+ logger = getLogger ("nipype.workflow" )
5671
5772
5873def _check_mem_x_path (mem_x_path ):
@@ -399,10 +414,9 @@ def run(self, updatehash=False):
399414 if self .seed is not None :
400415 self ._apply_random_seed ()
401416 if self .seed_applied :
402- random_state_logger .info ('%s' ,
403- '%s # (Atropos constant)' %
404- self .name if 'atropos' in
405- self .name else self .name )
417+ random_state_logger .info ('%s\t %s' , '# (Atropos constant)' if
418+ 'atropos' in self .name else
419+ str (self .seed ), self .name )
406420 return super ().run (updatehash )
407421
408422
@@ -483,6 +497,40 @@ def _configure_exec_nodes(self, graph):
483497 TypeError ):
484498 self ._handle_just_in_time_exception (node )
485499
500+ def connect_retries (self , nodes : Iterable ['Node' ],
501+ connections : Iterable [Tuple ['Node' , Union [str , tuple ],
502+ str ]]) -> None :
503+ """Method to generalize making the same connections to try and
504+ retry nodes.
505+
506+ For each 3-tuple (``conn``) in ``connections``, will do
507+ ``wf.connect(conn[0], conn[1], node, conn[2])`` for each ``node``
508+ in ``nodes``
509+
510+ Parameters
511+ ----------
512+ nodes : iterable of Nodes
513+
514+ connections : iterable of 3-tuples of (Node, str or tuple, str)
515+ """
516+ wrong_conn_type_msg = (r'connect_retries `connections` argument '
517+ 'must be an iterable of (Node, str or '
518+ 'tuple, str) tuples.' )
519+ if not isinstance (connections , (list , tuple )):
520+ raise TypeError (f'{ wrong_conn_type_msg } : Given { connections } ' )
521+ for node in nodes :
522+ if not isinstance (node , Node ):
523+ raise TypeError ('connect_retries requires an iterable '
524+ r'of nodes for the `nodes` parameter: '
525+ f'Given { node } ' )
526+ for conn in connections :
527+ if not all ((isinstance (conn , (list , tuple )), len (conn ) == 3 ,
528+ isinstance (conn [0 ], Node ),
529+ isinstance (conn [1 ], (tuple , str )),
530+ isinstance (conn [2 ], str ))):
531+ raise TypeError (f'{ wrong_conn_type_msg } : Given { conn } ' )
532+ self .connect (* conn [:2 ], node , conn [2 ])
533+
486534 def _handle_just_in_time_exception (self , node ):
487535 # pylint: disable=protected-access
488536 if hasattr (self , '_local_func_scans' ):
@@ -492,6 +540,32 @@ def _handle_just_in_time_exception(self, node):
492540 # TODO: handle S3 files
493541 node ._apply_mem_x (UNDEFINED_SIZE ) # noqa: W0212
494542
543+ def nodes_and_guardrails (self , * nodes , registered , add_clones = True ):
544+ """Returns a two tuples of Nodes: (try, retry) and their
545+ respective guardrails
546+
547+ Parameters
548+ ----------
549+ nodes : any number of Nodes
550+
551+ Returns
552+ -------
553+ nodes : tuple of Nodes
554+
555+ guardrails : tuple of Nodes
556+ """
557+ from CPAC .registration .guardrails import registration_guardrail_node , \
558+ retry_clone
559+ nodes = list (nodes )
560+ if add_clones is True :
561+ nodes .extend ([retry_clone (node ) for node in nodes ])
562+ guardrails = [None ] * len (nodes )
563+ for i , node in enumerate (nodes ):
564+ guardrails [i ] = registration_guardrail_node (
565+ f'guardrail_{ node .name } ' , i )
566+ self .connect (node , registered , guardrails [i ], 'registered' )
567+ return tuple (nodes ), tuple (guardrails )
568+
495569
496570def get_data_size (filepath , mode = 'xyzt' ):
497571 """Function to return the size of a functional image (x * y * z * t)
0 commit comments