code: def _run(
      self,
      discovery_schedule=None,
      exit_schedule=None,
      exit_mode="exception",
      num_proc=2,
      min_num_proc=2,
      max_num_proc=4,
      hosts=None,
      reset_limit=None,
      cooldown_range=None,
      epoch_wait=None,
      epochs=None,
  ):
      if not discovery_schedule and not hosts:
          raise ValueError(
              "at least one of discovery schedule or hosts must be given"
          )
  
      with temppath() as logfile:
          with _temp_discovery_script(
              logfile, discovery_schedule or [(None, hosts.split(","))]
          ) as discovery_script:
              command_args = [
                  "horovodrun",
                  "-np",
                  str(num_proc),
                  "--min-num-proc",
                  str(min_num_proc),
                  "--log-level",
                  "DEBUG",
              ]
              if hosts is not None:
                  command_args += ["-H", hosts]
              else:
                  command_args += [
                      "--host-discovery-script",
                      discovery_script,
                      "--max-num-proc",
                      str(max_num_proc),
                  ]
  
              if reset_limit is not None:
                  command_args += ["--reset-limit", str(reset_limit)]
  
              if cooldown_range is not None:
                  command_args += [
                      "--blacklist-cooldown-range",
                      str(cooldown_range[0]),
                      str(cooldown_range[1]),
                  ]
  
              command_args += [
                  "python",
                  self._training_script,
                  "--logfile",
                  logfile,
              ]
              if discovery_schedule:
                  command_args += [
                      "--discovery-schedule",
                      json.dumps(discovery_schedule),
                  ]
              if epoch_wait:
                  command_args += [
                      "--epoch-wait",
                      json.dumps(epoch_wait),
                  ]
              if epochs:
                  command_args += ["--epochs", json.dumps(epochs)]
              if exit_schedule:
                  command_args += [
                      "--exit-schedule",
                      json.dumps(exit_schedule),
                      "--exit-mode",
                      exit_mode,
                  ]
              print(" ".join(command_args))
  
              with override_args(*command_args):
                  args = parse_args()
                  env = {}
                  config_parser.set_env_from_args(env, args)
                  _run_elastic(args)
  
                  with open(logfile, "r") as f:
                      lines = f.readlines()
  
                  print("logfile:")
                  for line in lines:
                      print(line)
  
                  return [json.loads(line) for line in lines]
  
imports: import contextlib
  import json
  import os
  import sys
  from typing import Callable
  import mock
  import pytest
  from horovod.runner.common.util import config_parser
  from horovod.runner.elastic import constants
  from horovod.runner.launch import parse_args, _run_elastic
  from common import override_args, temppath
label_desc: Use image node_id 2 for calling the BaseElasticTests obj's underlying member method code with example usage: obj._run(discovery_schedule, exit_schedule, exit_mode, num_proc, min_num_proc, max_num_proc, hosts, reset_limit, cooldown_range, epoch_wait, epochs) and returns: unknown