56
56
DockerSpec ,
57
57
SingularitySpec ,
58
58
attr_fields ,
59
+ File ,
60
+ Directory ,
59
61
)
60
62
from .helpers import (
61
63
ensure_list ,
@@ -568,6 +570,7 @@ def __init__(
568
570
if input_spec is None :
569
571
input_spec = SpecInfo (name = "Inputs" , fields = [], bases = (ContainerSpec ,))
570
572
self .output_cpath = Path (output_cpath )
573
+ self .bindings = {}
571
574
super ().__init__ (
572
575
name = name ,
573
576
input_spec = input_spec ,
@@ -615,33 +618,12 @@ def bind_paths(self):
615
618
mount points: dict
616
619
mapping from local path to tuple of container path + mode
617
620
"""
618
- bind_paths = {}
619
- output_dir_cpath = None
620
- if self .inputs .bindings is None :
621
- self .inputs .bindings = []
621
+ self ._check_inputs ()
622
622
output_dir = self .output_dir
623
- # This part has to stay for now!!!
624
- # I'm creating self.inputs.bindings based on the input in TaskBase._run
625
- # in self.inputs.check_fields_input_spec() (see specs.py)
626
- for binding in self .inputs .bindings :
627
- binding = list (binding )
628
- if len (binding ) == 3 :
629
- lpath , cpath , mode = binding
630
- elif len (binding ) == 2 :
631
- lpath , cpath , mode = binding + ["rw" ]
632
- else :
633
- raise Exception (
634
- f"binding should have length 2, 3, or 4, it has { len (binding )} "
635
- )
636
- if Path (lpath ) == output_dir :
637
- output_dir_cpath = cpath
638
- if mode is None :
639
- mode = "rw" # default
640
- bind_paths [Path (lpath )] = (Path (cpath ), mode )
641
- # output_dir is added to the bindings if not part of self.inputs.bindings
642
- if not output_dir_cpath :
643
- bind_paths [output_dir ] = (self .output_cpath , "rw" )
644
- return bind_paths
623
+ # TODO: output dir should be always "rw"
624
+ if output_dir not in self .bindings :
625
+ self .bindings [output_dir ] = (self .output_cpath , "rw" )
626
+ return self .bindings
645
627
646
628
def binds (self , opt ):
647
629
"""
@@ -655,6 +637,38 @@ def binds(self, opt):
655
637
bargs .extend ([opt , f"{ lpath } :{ cpath } :{ mode } " ])
656
638
return bargs
657
639
640
+ def _check_inputs (self ):
641
+ fields = attr_fields (self .inputs )
642
+ for fld in fields :
643
+ if (
644
+ fld .type in [File , Directory ]
645
+ or "pydra.engine.specs.File" in str (fld .type )
646
+ or "pydra.engine.specs.Directory" in str (fld .type )
647
+ ):
648
+
649
+ if fld .name == "image" :
650
+ continue
651
+ file = Path (getattr (self .inputs , fld .name ))
652
+ if fld .metadata .get ("container_path" ):
653
+ # if the path is in a container the input should be treated as a str (hash as a str)
654
+ # field.type = "str"
655
+ # setattr(self, field.name, str(file))
656
+ pass
657
+ # if this is a local path, checking if the path exists
658
+ # TODO: if copyfile, ro -> rw
659
+ elif file .exists (): # is it ok if two inputs have the same parent?
660
+ self .bindings [Path (file .parent )] = (
661
+ Path (f"/pydra_inp_{ fld .name } " ),
662
+ "ro" ,
663
+ )
664
+ # error should be raised only if the type is strictly File or Directory
665
+ elif fld .type in [File , Directory ]:
666
+ raise FileNotFoundError (
667
+ f"the file { file } from { fld .name } input does not exist, "
668
+ f"if the file comes from the container, "
669
+ f"use field.metadata['container_path']=True"
670
+ )
671
+
658
672
659
673
class DockerTask (ContainerTask ):
660
674
"""Extend shell command task for containerized execution with the Docker Engine."""
0 commit comments