code: def _set_function_node_output(self, node_id, node_attr, no_call,
                                    next_nds=None, **kw):
          
  
          # Namespace shortcuts for speed.
          o_nds, dist = node_attr['outputs'], self.dist
  
          # List of nodes that can still be estimated by the function node.
          output_nodes = next_nds or set(self._succ[node_id]).difference(dist)
  
          if not output_nodes:  # This function is not needed.
              self.workflow.remove_node(node_id)  # Remove function node.
              return False
  
          wf_add_edge = self._wf_add_edge  # Namespace shortcuts for speed.
  
          if no_call:
              for u in output_nodes:  # Set workflow out.
                  wf_add_edge(node_id, u)
              return True
  
          args = self._wf_pred[node_id]  # List of the function's arguments.
          args = [args[k]['value'] for k in node_attr['inputs']]
  
          try:
              self._check_function_domain(args, node_attr, node_id)
              res = async_thread(self, args, node_attr, node_id, **kw)
              # noinspection PyUnresolvedReferences
              self.workflow.node[node_id]['results'] = res
          except SkipNode:
              return False
  
          # Set workflow.
          for k, v in zip(o_nds, res if len(o_nds) > 1 else [res]):
              if k in output_nodes and v is not NONE:
                  wf_add_edge(node_id, k, value=v)
  
          return True
docs: Set the function node output from node inputs.
  
          :param node_id:
              Function node id.
          :type node_id: str
  
          :param node_attr:
              Dictionary of node attributes.
          :type node_attr: dict[str, T]
  
          :param no_call:
              If True data node estimation function is not used.
          :type no_call: bool
  
          :return:
              If the output have been evaluated correctly.
          :rtype: bool