class_docstr: The execution engine will run every model in the current process.
  If multiple models have been submitted, they will be queued and run sequentially.
  
  Keyboard interrupt will terminate the currently running model and raise to let the main process know.
class_docstr_tok: ["The","execution","engine","will","run","every","model","in","the","current","process",".","If","multiple","models","have","been","submitted",",","they","will","be","queued","and","run","sequentially",".","Keyboard","interrupt","will","terminate","the","currently","running","model","and","raise","to","let","the","main","process","know","."]
code: def _run_single_model(self, model: ExecutableModelSpace) -> None:
      model.status = ModelStatus.Training
      start_time = time.time()
      _prev_channel = get_default_trial_command_channel()
      try:
          # Reset the channel to overwrite get_next_parameter() and report_xxx_result()
          _channel = SequentialTrialCommandChannel(self, model)
          set_default_trial_command_channel(_channel)
          # Set the current parameter
          parameters = nni.get_next_parameter()
          assert parameters is model
          # Run training.
          model.execute()
          # Training success.
          status = ModelStatus.Trained
          duration = time.time() - start_time
          self._total_duration += duration
          _logger.debug(
              "Execution time of model %d: %.2f seconds (total %.2f)",
              self._model_count,
              duration,
              self._total_duration,
          )
      except KeyboardInterrupt:
          # Training interrupted.
          duration = time.time() - start_time
          self._total_duration += duration
          _logger.error(
              "Model %d is interrupted. Exiting gracefully...",
              self._model_count,
          )
          status = ModelStatus.Interrupted
          raise
      except:
          # Training failed.
          _logger.error(
              "Model %d fails to be executed.", self._model_count
          )
          duration = time.time() - start_time
          self._total_duration += duration
          status = ModelStatus.Failed
          if self.continue_on_failure:
              _logger.error(traceback.format_exc())
              _logger.error(
                  "Continue on failure. Skipping to next model."
              )
          else:
              raise
      finally:
          # Restore the trial command channel.
          set_default_trial_command_channel(_prev_channel)
  
          # Sometimes, callbacks could do heavy things here, e.g., retry the model.
          # So the callback should only be done at the very very end.
          # And we don't catch exceptions happen inside.
          self.dispatch_model_event(
              TrainingEndEvent(model, status)
          )  # pylint: disable=used-before-assignment
          _logger.debug(
              "Training end callbacks of model %d are done.",
              self._model_count,
          )
  
imports: from __future__ import annotations
  import logging
  import time
  import traceback
  from typing import Iterable, List, cast
  from typing_extensions import Literal
  import nni
  from nni.runtime.trial_command_channel import set_default_trial_command_channel, get_default_trial_command_channel, TrialCommandChannel
  from nni.nas.space import ExecutableModelSpace, ModelStatus
  from nni.typehint import ParameterRecord, Parameters, TrialMetric
  from .engine import ExecutionEngine
  from .event import FinalMetricEvent, IntermediateMetricEvent, TrainingEndEvent
label_desc: Use image node_id 2 for calling the SequentialExecutionEngine obj's underlying member method code with example usage: obj._run_single_model(model) without return types