@@ -297,37 +297,69 @@ def from_list_if_single(obj: ty.Any) -> ty.Any:
297297 return obj
298298
299299
300- def task_help (defn : "Task[TaskType]" , to_list : bool = False ) -> list [str ] | None :
300+ def fold_text (text : str , width : int = 70 ) -> str :
301+ """Fold text to a given width, respecting word boundaries."""
302+ if not isinstance (text , str ):
303+ return text
304+ if len (text ) <= width :
305+ return text
306+ lines = []
307+ for line in text .splitlines ():
308+ while len (line ) > width :
309+ words = line .split ()
310+ split_line = ""
311+ for word in words :
312+ if len (split_line ) + len (word ) + 1 > width :
313+ lines .append (split_line .strip ())
314+ split_line = ""
315+ split_line += word + " "
316+ lines .append (split_line .strip ())
317+ lines .append (line )
318+ return "\n " .join (lines )
319+
320+
321+ def task_help (task_type : "type[Task] | Task" , line_width : int = 79 ) -> list [str ] | None :
301322 """Visit a job object and print its input/output interface."""
302- from pydra .compose .base import NO_DEFAULT
303-
304- lines = [f"Help for { defn .__class__ .__name__ } " ]
305- if task_fields (defn ):
306- lines += ["Input Parameters:" ]
307- for f in task_fields (defn ):
308- if (defn ._task_type == "python" and f .name == "function" ) or (
309- defn ._task_type == "workflow" and f .name == "constructor"
310- ):
311- continue
312- default = ""
313- if f .default is not NO_DEFAULT and not f .name .startswith ("_" ):
314- default = f" (default: { f .default } )"
315- try :
316- name = f .type .__name__
317- except AttributeError :
318- name = str (f .type )
319- lines += [f"- { f .name } : { name } { default } " ]
320- output_klass = defn .Outputs
321- if task_fields (output_klass ):
322- lines += ["Output Parameters:" ]
323- for f in task_fields (output_klass ):
323+ from pydra .compose .base import Task , NO_DEFAULT
324+
325+ if isinstance (task_type , Task ):
326+ task_type = type (task_type )
327+
328+ def field_listing (field : "Field" ) -> str :
329+ """Get the field listing for a task."""
324330 try :
325- name = f .type .__name__
331+ type_str = field .type .__name__
326332 except AttributeError :
327- name = str (f .type )
328- lines += [f"- { f .name } : { name } " ]
329- if to_list :
330- return lines
333+ type_str = str (field .type )
334+ field_str = f"- { field .name } : { type_str } "
335+ if isinstance (field .default , attrs .Factory ):
336+ field_str += f" (factory: { field .default .factory .__name__ } )"
337+ elif callable (field .default ):
338+ field_str += f" (default: { field .default .__name__ } ())"
339+ elif field .default is not NO_DEFAULT :
340+ field_str += f" (default: { field .default } )"
341+ if field .help :
342+ field_str += f"\n { fold_text (field .help , width = line_width - 4 )} "
343+ return field_str
344+
345+ lines = [f"Help for '{ task_type .__name__ } ' tasks" ]
346+ lines .append ("-" * len (lines [0 ]))
347+ inputs = task_fields (task_type )
348+ if inputs :
349+ lines .append ("Inputs:" )
350+ for inpt in inputs :
351+ lines .append (field_listing (inpt ))
352+ outputs = task_fields (task_type .Outputs )
353+ if outputs :
354+ lines .append ("Outputs:" )
355+ for output in outputs :
356+ lines .append (field_listing (output ))
357+ return lines
358+
359+
360+ def print_help (task : "Task[TaskType]" ) -> None :
361+ """Print help for a task."""
362+ lines = task_help (task )
331363 print ("\n " .join (lines ))
332364
333365
0 commit comments