code: def _recursively_check_required_components(
      node_name: Text, schema: GraphSchema
  ) -> Tuple[Dict[Type, Set[Text]], Set[Type]]:
      """Collects unmet requirements and types used in the subtree rooted at `node_name`.
  
      Args:
          schema: the graph schema
          node_name: the name of the root of the subtree
      Returns:
         unmet requirements, i.e. a mapping from component types to names of nodes that
         are contained in the subtree rooted at `schema_node` that require that component
         type but can't find it in their respective subtrees and
         a set containing all component types of nodes that are ancestors of the
         `schema_node` (or of the`schema_node` itself)
      """
      schema_node = schema.nodes[node_name]
  
      unmet_requirements: Dict[Type, Set[Text]] = dict()
      component_types = set()
  
      # collect all component types used by ancestors and their unmet requirements
      for parent_node_name in schema_node.needs.values():
          if _is_placeholder_input(parent_node_name):
              continue
          (
              unmet_requirements_of_ancestors,
              ancestor_types,
          ) = _recursively_check_required_components(
              node_name=parent_node_name, schema=schema
          )
          for _type, nodes in unmet_requirements_of_ancestors.items():
              unmet_requirements.setdefault(_type, set()).update(nodes)
          component_types.update(ancestor_types)
  
      # check which requirements of the `schema_node` are not fulfilled by
      # comparing its requirements with the types found so far among the ancestor nodes
      unmet_requirements_of_current_node = set(
          required
          for required in schema_node.uses.required_components()
          if not any(
              issubclass(used_subtype, required)
              for used_subtype in component_types
          )
      )
  
      # add the unmet requirements and the type of the `schema_node`
      for component_type in unmet_requirements_of_current_node:
          unmet_requirements.setdefault(component_type, set()).add(
              node_name
          )
      component_types.add(schema_node.uses)
  
      return unmet_requirements, component_types
  
imports: import inspect
  import logging
  import typing
  from typing import Optional, Callable, Text, Tuple, Dict, Type, Any, Set, Union, TypeVar, List
  import dataclasses
  from rasa.core.policies.policy import PolicyPrediction
  from rasa.engine.training.fingerprinting import Fingerprintable
  import rasa.utils.common
  import typing_utils
  from rasa.engine.exceptions import GraphSchemaValidationException
  from rasa.engine.graph import GraphSchema, GraphComponent, SchemaNode, ExecutionContext, GraphModelConfiguration
  from rasa.engine.constants import RESERVED_PLACEHOLDERS
  from rasa.engine.storage.resource import Resource
  from rasa.engine.storage.storage import ModelStorage
  from rasa.shared.constants import DOCS_URL_GRAPH_COMPONENTS
  from rasa.shared.exceptions import RasaException
  from rasa.shared.nlu.training_data.message import Message
label_desc: Use image node_id 23 for calling a global function with example usage: _recursively_check_required_components(node_name, schema) and returns: unmet_requirements,  component_types