docstr: Take a workflow object and use introspection to extract the
  parameters, types and docstrings of its run method. Then add these
  parameters to the current arparser's own params to parse. If the
  workflow is of type combined_workflow, the optional input parameters
  of its sub workflows will also be added.
  
  Parameters
  ----------
  workflow : dipy.workflows.workflow.Workflow
      Workflow from which to infer parameters.
  
  Returns
  -------
  sub_flow_optionals : dictionary of all sub workflow optional parameters
docstr_tok: ["Take","a","workflow","object","and","use","introspection","to","extract","the","parameters",",","types","and","docstrings","of","its","run","method",".","Then","add","these","parameters","to","the","current","arparser","'s","own","params","to","parse",".","If","the","workflow","is","of","type","combined_workflow",",","the","optional","input","parameters","of","its","sub","workflows","will","also","be","added",".","Parameters","--","--","--","--","--","workflow",":","dipy.workflows.workflow.Workflow","Workflow","from","which","to","infer","parameters",".","Returns","--","--","--","-","sub_flow_optionals",":","dictionary","of","all","sub","workflow","optional","parameters"]
code: def add_workflow(self, workflow):
      """Take a workflow object and use introspection to extract the
      parameters, types and docstrings of its run method. Then add these
      parameters to the current arparser's own params to parse. If the
      workflow is of type combined_workflow, the optional input parameters
      of its sub workflows will also be added.
  
      Parameters
      ----------
      workflow : dipy.workflows.workflow.Workflow
          Workflow from which to infer parameters.
  
      Returns
      -------
      sub_flow_optionals : dictionary of all sub workflow optional parameters
      """
  
      doc = inspect.getdoc(workflow.run)
      npds = NumpyDocString(doc)
      self.doc = npds["Parameters"]
      self.description = "{0}\n\n{1}".format(
          " ".join(npds["Summary"]), " ".join(npds["Extended Summary"])
      )
  
      if npds["References"]:
          ref_text = [text or "\n" for text in npds["References"]]
          ref_idx = self.epilog.find("References: \n") + len(
              "References: \n"
          )
          self.epilog = "{0}{1}\n{2}".format(
              self.epilog[:ref_idx],
              "".join(ref_text),
              self.epilog[ref_idx:],
          )
  
      self._output_params = [
          param for param in npds["Parameters"] if "out_" in param[0]
      ]
      self._positional_params = [
          param
          for param in npds["Parameters"]
          if "optional" not in param[1] and "out_" not in param[0]
      ]
      self._optional_params = [
          param
          for param in npds["Parameters"]
          if "optional" in param[1]
      ]
  
      args, defaults = get_args_default(workflow.run)
  
      output_args = self.add_argument_group(
          "output arguments(optional)"
      )
  
      len_args = len(args)
      len_defaults = len(defaults)
      nb_positional_variable = 0
  
      if len_args != len(self.doc):
          raise ValueError(
              self.prog + ": Number of parameters in the "
              "doc string and run method does not match. "
              "Please ensure that the number of parameters "
              "in the run method is same as the doc string."
          )
  
      for i, arg in enumerate(args):
          prefix = ""
          is_optional = i >= len_args - len_defaults
          if is_optional:
              prefix = "--"
  
          typestr = self.doc[i][1]
          dtype, isnarg = self._select_dtype(typestr)
          help_msg = " ".join(self.doc[i][2])
  
          _args = ["{0}{1}".format(prefix, arg)]
          _kwargs = {"help": help_msg, "type": dtype, "action": "store"}
  
          if is_optional:
              _kwargs["metavar"] = dtype.__name__
              if dtype is bool:
                  _kwargs["action"] = "store_true"
                  default_ = dict()
                  default_[arg] = False
                  self.set_defaults(**default_)
                  del _kwargs["type"]
                  del _kwargs["metavar"]
          elif dtype is bool:
              _kwargs["type"] = int
              _kwargs["choices"] = [0, 1]
  
          if dtype is tuple:
              _kwargs["type"] = str
  
          if isnarg:
              if is_optional:
                  _kwargs["nargs"] = "*"
              else:
                  _kwargs["nargs"] = "+"
                  nb_positional_variable += 1
  
          if "out_" in arg:
              output_args.add_argument(*_args, **_kwargs)
          else:
              if _kwargs["action"] != "store_true":
                  _kwargs["type"] = none_or_dtype(_kwargs["type"])
              self.add_argument(*_args, **_kwargs)
  
      if nb_positional_variable > 1:
          raise ValueError(
              self.prog + " : All positional arguments present"
              " are gathered into a list. It does not make"
              "much sense to have more than one positional"
              " argument with 'variable string' as dtype."
              " Please, ensure that 'variable (type)'"
              " appears only once as a positional argument."
          )
  
      return self.add_sub_flow_args(workflow.get_sub_runs())
  
file_path: dipy/dipy/workflows/base.py
imports: import argparse
  import inspect
  from dipy.workflows.docstring_parser import NumpyDocString
label_desc: Use image node_id 2 for calling the IntrospectiveArgumentParser obj's underlying member method code with example usage: obj.add_workflow(workflow) and returns: self