1414 ensure_list ,
1515 PYDRA_ATTR_METADATA ,
1616 list_fields ,
17+ is_lazy ,
1718)
1819from pydra .utils .typing import (
1920 MultiInputObj ,
2021 MultiInputFile ,
2122 MultiOutputObj ,
2223 MultiOutputFile ,
2324)
24- from pydra .engine .workflow .lazy import LazyField
2525
2626
2727if ty .TYPE_CHECKING :
28- from pydra .engine .specs import OutputsSpec
28+ from pydra .engine .specs import TaskSpec , OutSpec
2929 from pydra .engine .core import Task
3030
3131__all__ = [
@@ -84,7 +84,9 @@ class Field:
8484 validator = is_type , default = ty .Any , converter = default_if_none (ty .Any )
8585 )
8686 help_string : str = ""
87- requires : list | None = None
87+ requires : list [str ] | list [list [str ]] = attrs .field (
88+ factory = list , converter = ensure_list
89+ )
8890 converter : ty .Callable | None = None
8991 validator : ty .Callable | None = None
9092
@@ -240,6 +242,8 @@ def get_fields(klass, field_type, auto_attribs, helps) -> dict[str, Field]:
240242
241243
242244def make_task_spec (
245+ spec_type : type ["TaskSpec" ],
246+ out_type : type ["OutSpec" ],
243247 task_type : type ["Task" ],
244248 inputs : dict [str , Arg ],
245249 outputs : dict [str , Out ],
@@ -281,14 +285,16 @@ def make_task_spec(
281285
282286 if name is None and klass is not None :
283287 name = klass .__name__
284- outputs_klass = make_outputs_spec (outputs , outputs_bases , name )
285- if klass is None or not issubclass (klass , TaskSpec ):
288+ outputs_klass = make_outputs_spec (out_type , outputs , outputs_bases , name )
289+ if klass is None or not issubclass (klass , spec_type ):
286290 if name is None :
287291 raise ValueError ("name must be provided if klass is not" )
292+ if klass is not None and issubclass (klass , TaskSpec ):
293+ raise ValueError (f"Cannot change type of spec { klass } to { spec_type } " )
288294 bases = tuple (bases )
289295 # Ensure that TaskSpec is a base class
290- if not any (issubclass (b , TaskSpec ) for b in bases ):
291- bases = bases + (TaskSpec ,)
296+ if not any (issubclass (b , spec_type ) for b in bases ):
297+ bases = bases + (spec_type ,)
292298 # If building from a decorated class (as opposed to dynamically from a function
293299 # or shell-template), add any base classes not already in the bases tuple
294300 if klass is not None :
@@ -346,8 +352,11 @@ def make_task_spec(
346352
347353
348354def make_outputs_spec (
349- outputs : dict [str , Out ], bases : ty .Sequence [type ], spec_name : str
350- ) -> type ["OutputsSpec" ]:
355+ spec_type : type ["OutSpec" ],
356+ outputs : dict [str , Out ],
357+ bases : ty .Sequence [type ],
358+ spec_name : str ,
359+ ) -> type ["OutSpec" ]:
351360 """Create an outputs specification class and its outputs specification class from the
352361 output fields provided to the decorator/function.
353362
@@ -368,10 +377,14 @@ def make_outputs_spec(
368377 klass : type
369378 The class created using the attrs package
370379 """
371- from pydra .engine .specs import OutputsSpec
380+ from pydra .engine .specs import OutSpec
372381
373- if not any (issubclass (b , OutputsSpec ) for b in bases ):
374- outputs_bases = bases + (OutputsSpec ,)
382+ if not any (issubclass (b , spec_type ) for b in bases ):
383+ if out_spec_bases := [b for b in bases if issubclass (b , OutSpec )]:
384+ raise ValueError (
385+ f"Cannot make { spec_type } output spec from { out_spec_bases } bases"
386+ )
387+ outputs_bases = bases + (spec_type ,)
375388 if reserved_names := [n for n in outputs if n in RESERVED_OUTPUT_NAMES ]:
376389 raise ValueError (
377390 f"{ reserved_names } are reserved and cannot be used for output field names"
@@ -549,7 +562,7 @@ def make_validator(field: Field, interface_name: str) -> ty.Callable[..., None]
549562def allowed_values_validator (_ , attribute , value ):
550563 """checking if the values is in allowed_values"""
551564 allowed = attribute .metadata [PYDRA_ATTR_METADATA ].allowed_values
552- if value is attrs .NOTHING or isinstance (value , LazyField ):
565+ if value is attrs .NOTHING or is_lazy (value ):
553566 pass
554567 elif value not in allowed :
555568 raise ValueError (
0 commit comments