code: def wait_for_nodes(self, num_nodes: int, timeout: float = 900):
      # Wait script should be uploaded already. Kick off command
      try:
          # Give 30 seconds more to acount for communication
          self.run_prepare_command(
              f"python wait_cluster.py {num_nodes} {timeout}",
              timeout=timeout + 30,
          )
      except (CommandError, CommandTimeout) as e:
          raise ClusterNodesWaitTimeout(
              f"Not all {num_nodes} nodes came up within {timeout} seconds."
          ) from e
  
imports: import json
  import os
  import tempfile
  from typing import TYPE_CHECKING, Any, Dict, Optional
  from ray_release.cluster_manager.cluster_manager import ClusterManager
  from ray_release.command_runner.command_runner import CommandRunner
  from ray_release.exception import ClusterNodesWaitTimeout, CommandError, CommandTimeout, LocalEnvSetupError, LogsError, FetchResultError
  from ray_release.file_manager.file_manager import FileManager
  from ray_release.job_manager import JobManager
  from ray_release.logger import logger
  from ray_release.util import format_link, get_anyscale_sdk
  from ray_release.wheels import install_matching_ray_locally
label_desc: Use image node_id 5 for calling the JobRunner obj's underlying member method code with example usage: obj.wait_for_nodes(num_nodes, timeout) without return types