class_docstr: Base class used for composite model structure definition
  
  Args:
      nodes: :obj:`PipelineNode` object(s)
      use_input_preprocessing: whether to do input preprocessing or not, ``True`` by default.
docstr: In case of provided ``input_data`` is of type :class:`MultiModalData`
  assigns :attr:`PipelineNode.node_data` from the ``input_data`` if ``PipelineNode.nodes_from`` is None
  
  Args:
      input_data: data to assign to :attr:`PipelineNode.node_data`
  
  Returns:
      ``None`` in case of :class:`MultiModalData` and ``input_data`` otherwise
docstr_tok: ["In","case","of","provided","``","input_data","``","is","of","type",":","class",":","`","MultiModalData","`","assigns",":","attr",":","`","PipelineNode.node_data","`","from","the","``","input_data","``","if","``","PipelineNode.nodes_from","``","is","None","Args",":","input_data",":","data","to","assign","to",":","attr",":","`","PipelineNode.node_data","`","Returns",":","``","None","``","in","case","of",":","class",":","`","MultiModalData","`","and","``","input_data","``","otherwise"]
code: def _assign_data_to_nodes(
      self, input_data: Union[InputData, MultiModalData]
  ) -> Optional[InputData]:
      """In case of provided ``input_data`` is of type :class:`MultiModalData`
      assigns :attr:`PipelineNode.node_data` from the ``input_data`` if ``PipelineNode.nodes_from`` is None
  
      Args:
          input_data: data to assign to :attr:`PipelineNode.node_data`
  
      Returns:
          ``None`` in case of :class:`MultiModalData` and ``input_data`` otherwise
      """
  
      if isinstance(input_data, MultiModalData):
          for node in (
              n
              for n in self.nodes
              if (isinstance(n, PipelineNode) and n.is_primary)
          ):
              if node.operation.operation_type in input_data:
                  node.node_data = input_data[
                      node.operation.operation_type
                  ]
                  node.direct_set = True
              else:
                  raise ValueError(f"No data for primary node {node}")
          return None
      return input_data
  
imports: from copy import deepcopy
  from datetime import timedelta
  from os import PathLike
  from typing import Optional, Tuple, Union, Sequence, List, Dict
  import func_timeout
  from golem.core.dag.graph import Graph
  from golem.core.dag.graph_delegate import GraphDelegate
  from golem.core.dag.graph_node import GraphNode
  from golem.core.dag.graph_utils import distance_to_primary_level, graph_structure
  from golem.core.dag.linked_graph import LinkedGraph
  from golem.core.log import default_log
  from golem.core.optimisers.timer import Timer
  from golem.core.paths import copy_doc
  from golem.utilities.serializable import Serializable
  from golem.visualisation.graph_viz import NodeColorType
  from fedot.core.caching.pipelines_cache import OperationsCache
  from fedot.core.caching.preprocessing_cache import PreprocessingCache
  from fedot.core.data.data import InputData, OutputData
  from fedot.core.data.multi_modal import MultiModalData
  from fedot.core.operations.data_operation import DataOperation
  from fedot.core.operations.model import Model
  from fedot.core.pipelines.node import PipelineNode
  from fedot.core.pipelines.template import PipelineTemplate
  from fedot.core.repository.tasks import TaskTypesEnum
  from fedot.core.visualisation.pipeline_specific_visuals import PipelineVisualizer
  from fedot.preprocessing.dummy_preprocessing import DummyPreprocessor
  from fedot.preprocessing.preprocessing import DataPreprocessor
label_desc: Use image node_id 18 for calling the Pipeline obj's underlying member method code with example usage: obj._assign_data_to_nodes(input_data) and returns: input_data, None