code: def test_loop_restart_progress_multiple_dataloaders(
      tmpdir, n_dataloaders, stop_dataloader, stop_epoch, stop_batch
  ):
      n_batches = 5
      n_epochs = 3
  
      class ValidationModel(BoringModel):
          def __init__(self):
              super().__init__()
  
          def validation_step(self, batch, batch_idx, dataloader_idx):
              if (
                  self.current_epoch == stop_epoch
                  and batch_idx == stop_batch
                  and dataloader_idx == stop_dataloader
              ):
                  raise CustomException
              return super().validation_step(batch, batch_idx)
  
          def val_dataloader(self):
              return [
                  super(ValidationModel, self).val_dataloader()
                  for _ in range(n_dataloaders)
              ]
  
      model = ValidationModel()
  
      trainer = Trainer(
          default_root_dir=tmpdir,
          max_epochs=n_epochs,
          limit_train_batches=1,
          limit_val_batches=n_batches,
          callbacks=OnExceptionCheckpoint(tmpdir),
      )
  
      # simulate a failure
      with pytest.raises(CustomException):
          trainer.fit(model)
  
      ckpt_path = str(tmpdir / "on_exception.ckpt")
      checkpoint = torch.load(ckpt_path)["loops"]["fit_loop"]
  
      trainer.fit_loop.load_state_dict(checkpoint)
  
      # `nbe_`: non-breaking epoch, as in, no exception will be raised. `be_`: breaking epoch
      # the fit-validation total batch progress is reset per epoch so it's not counted for the total value.
      nbe_total_val_batch = 0  # stop_epoch * n_dataloaders * n_batches
      be_total_val_batch = stop_dataloader * n_batches + stop_batch
      total_val_batch = nbe_total_val_batch + be_total_val_batch
      expected = {
          "total": {
              "ready": total_val_batch + 1,
              "started": total_val_batch + 1,
              "processed": total_val_batch,
              "completed": total_val_batch,
          },
          "current": {
              "ready": total_val_batch + 1,
              "started": total_val_batch + 1,
              "processed": total_val_batch,
              "completed": total_val_batch,
          },
          "is_last_batch": False,
      }
      assert (
          trainer.fit_loop.epoch_loop.val_loop.batch_progress.state_dict()
          == expected
      )
  
imports: import os
  from copy import deepcopy
  from dataclasses import dataclass
  from typing import Dict, Iterator
  from unittest.mock import ANY, Mock
  import pytest
  import torch
  from lightning.pytorch import LightningModule, Trainer
  from lightning.pytorch.callbacks import Callback, ModelCheckpoint, OnExceptionCheckpoint
  from lightning.pytorch.demos.boring_classes import BoringModel, RandomDataset
  from lightning.pytorch.loops import _Loop
  from lightning.pytorch.loops.progress import _BaseProgress
  from torch.utils.data.dataloader import DataLoader, _MultiProcessingDataLoaderIter
  from tests_pytorch.helpers.runif import RunIf
label_desc: Use image node_id 4 for calling a global function with example usage: test_loop_restart_progress_multiple_dataloaders(tmpdir, n_dataloaders, stop_dataloader, stop_epoch, stop_batch) and returns: super, unknown