@@ -464,13 +464,25 @@ def __call__(
464
464
return res
465
465
466
466
def _modify_inputs (self ):
467
- """Update and preserve a Task's original inputs"""
467
+ """This method modifies the inputs of the task ahead of its execution:
468
+ - links/copies upstream files and directories into the destination tasks
469
+ working directory as required select state array values corresponding to
470
+ state index (it will try to leave them where they are unless specified or
471
+ they are on different file systems)
472
+ - resolve template values (e.g. output_file_template)
473
+ - deepcopy all inputs to guard against in-place changes during the task's
474
+ execution (they will be replaced after the task's execution with the
475
+ original inputs to ensure the tasks checksums are consistent)
476
+ """
468
477
orig_inputs = {
469
- k : deepcopy (v ) for k , v in attr .asdict (self .inputs , recurse = False ).items ()
478
+ k : v
479
+ for k , v in attr .asdict (self .inputs , recurse = False ).items ()
480
+ if not k .startswith ("_" )
470
481
}
471
482
map_copyfiles = {}
472
- for fld in attr_fields (self .inputs ):
473
- value = getattr (self .inputs , fld .name )
483
+ input_fields = attr .fields (type (self .inputs ))
484
+ for name , value in orig_inputs .items ():
485
+ fld = getattr (input_fields , name )
474
486
copy_mode , copy_collation = parse_copyfile (
475
487
fld , default_collation = self .DEFAULT_COPY_COLLATION
476
488
)
@@ -485,11 +497,21 @@ def _modify_inputs(self):
485
497
supported_modes = self .SUPPORTED_COPY_MODES ,
486
498
)
487
499
if value is not copied_value :
488
- map_copyfiles [fld . name ] = copied_value
500
+ map_copyfiles [name ] = copied_value
489
501
modified_inputs = template_update (
490
502
self .inputs , self .output_dir , map_copyfiles = map_copyfiles
491
503
)
492
- for name , value in modified_inputs .items ():
504
+ assert all (m in orig_inputs for m in modified_inputs ), (
505
+ "Modified inputs contain fields not present in original inputs. "
506
+ "This is likely a bug."
507
+ )
508
+ for name , orig_value in orig_inputs .items ():
509
+ try :
510
+ value = modified_inputs [name ]
511
+ except KeyError :
512
+ # Ensure we pass a copy not the original just in case inner
513
+ # attributes are modified during execution
514
+ value = deepcopy (orig_value )
493
515
setattr (self .inputs , name , value )
494
516
return orig_inputs
495
517
@@ -550,11 +572,9 @@ def _run(self, rerun=False, environment=None, **kwargs):
550
572
save (output_dir , result = result , task = self )
551
573
# removing the additional file with the checksum
552
574
(self .cache_dir / f"{ self .uid } _info.json" ).unlink ()
553
- # # function etc. shouldn't change anyway, so removing
554
575
# Restore original values to inputs
555
576
for field_name , field_value in orig_inputs .items ():
556
- if not field_name .startswith ("_" ):
557
- setattr (self .inputs , field_name , field_value )
577
+ setattr (self .inputs , field_name , field_value )
558
578
os .chdir (cwd )
559
579
self .hooks .post_run (self , result )
560
580
# Check for any changes to the input hashes that have occurred during the execution
0 commit comments