@@ -345,7 +345,11 @@ def _command_args_single(self, state_ind=None, index=None):
345
345
exclude_names = ("container" , "image" , "container_xargs" , "bindings" ),
346
346
):
347
347
name , meta = field .name , field .metadata
348
- if getattr (self .inputs , name ) is attr .NOTHING and not meta .get ("readonly" ):
348
+ if (
349
+ getattr (self .inputs , name ) is attr .NOTHING
350
+ and not meta .get ("readonly" )
351
+ and not meta .get ("formatter" )
352
+ ):
349
353
continue
350
354
if name == "executable" :
351
355
pos_args .append (
@@ -404,8 +408,9 @@ def _command_pos_args(self, field, state_ind, index):
404
408
the specific field.
405
409
"""
406
410
argstr = field .metadata .get ("argstr" , None )
407
- if argstr is None :
408
- # assuming that input that has no arstr is not used in the command
411
+ formatter = field .metadata .get ("formatter" , None )
412
+ if argstr is None and formatter is None :
413
+ # assuming that input that has no arstr is not used in the command, or a formatter is not provided too.
409
414
return None
410
415
pos = field .metadata .get ("position" , None )
411
416
if pos is not None :
@@ -426,11 +431,45 @@ def _command_pos_args(self, field, state_ind, index):
426
431
value = self ._field_value (field , state_ind , index , check_file = True )
427
432
if field .metadata .get ("readonly" , False ) and value is not None :
428
433
raise Exception (f"{ field .name } is read only, the value can't be provided" )
429
- elif value is None and not field .metadata .get ("readonly" , False ):
434
+ elif (
435
+ value is None
436
+ and not field .metadata .get ("readonly" , False )
437
+ and formatter is None
438
+ ):
430
439
return None
431
440
441
+ # getting stated inputs
442
+ inputs_dict_st = attr .asdict (self .inputs )
443
+ if state_ind is not None :
444
+ for k , v in state_ind .items ():
445
+ k = k .split ("." )[1 ]
446
+ inputs_dict_st [k ] = inputs_dict_st [k ][v ]
447
+
432
448
cmd_add = []
433
- if field .type is bool :
449
+ # formatter that creates a custom command argument
450
+ # it can thake the value of the filed, all inputs, or the value of other fields.
451
+ if "formatter" in field .metadata :
452
+ call_args = inspect .getargspec (field .metadata ["formatter" ])
453
+ call_args_val = {}
454
+ for argnm in call_args .args :
455
+ if argnm == "field" :
456
+ call_args_val [argnm ] = value
457
+ elif argnm == "inputs" :
458
+ call_args_val [argnm ] = inputs_dict_st
459
+ else :
460
+ if argnm in inputs_dict_st :
461
+ call_args_val [argnm ] = inputs_dict_st [argnm ]
462
+ else :
463
+ raise AttributeError (
464
+ f"arguments of the formatter function from { field .name } "
465
+ f"has to be in inputs or be field or output_dir, "
466
+ f"but { argnm } is used"
467
+ )
468
+ cmd_el_str = field .metadata ["formatter" ](** call_args_val )
469
+ cmd_el_str = cmd_el_str .strip ().replace (" " , " " )
470
+ if cmd_el_str != "" :
471
+ cmd_add += cmd_el_str .split (" " )
472
+ elif field .type is bool :
434
473
# if value is simply True the original argstr is used,
435
474
# if False, nothing is added to the command
436
475
if value is True :
0 commit comments