code: def test_trainer_model_hook_system_fit(
      override_on_validation_model_train,
      automatic_optimization,
      kwargs,
      tmpdir,
  ):
      called = []
  
      class TestModel(HookedModel):
          def __init__(self, *args):
              super().__init__(*args)
              self.automatic_optimization = automatic_optimization
  
          def training_step(self, batch, batch_idx):
              if self.automatic_optimization:
                  return super().training_step(batch, batch_idx)
              loss = self.step(batch[0])
              opt = self.optimizers()
              opt.zero_grad()
              self.manual_backward(loss)
              opt.step(lambda: called.append({"name": "closure"}))
              return {"loss": loss}
  
      model = TestModel(called)
  
      if not override_on_validation_model_train:
          model.on_validation_model_train = None
      assert (
          is_overridden("on_validation_model_train", model)
          == override_on_validation_model_train
      )
  
      callback = HookedCallback(called)
      train_batches = 2
      val_batches = 2
      trainer = Trainer(
          default_root_dir=tmpdir,
          max_epochs=1,
          limit_train_batches=train_batches,
          limit_val_batches=val_batches,
          enable_progress_bar=False,
          enable_model_summary=False,
          callbacks=[callback],
          **kwargs,
      )
      trainer.fit(model)
      saved_ckpt = {
          "callbacks": ANY,
          "epoch": 0,
          "global_step": train_batches,
          "lr_schedulers": ANY,
          "optimizer_states": ANY,
          "pytorch-lightning_version": __version__,
          "state_dict": ANY,
          "loops": ANY,
      }
      using_deepspeed = kwargs.get("strategy") == "deepspeed"
      if kwargs.get("precision") == "16-mixed" and not using_deepspeed:
          saved_ckpt[
              trainer.precision_plugin.__class__.__qualname__
          ] = ANY
      device = trainer.strategy.root_device
      expected = [
          {"name": "configure_callbacks"},
          {"name": "prepare_data"},
          {
              "name": "Callback.setup",
              "args": (trainer, model),
              "kwargs": {"stage": "fit"},
          },
          {"name": "setup", "kwargs": {"stage": "fit"}},
          # DeepSpeed needs the batch size to figure out throughput logging
          *([{"name": "train_dataloader"}] if using_deepspeed else []),
          {"name": "configure_model"},
          {"name": "configure_optimizers"},
          {"name": "Callback.on_fit_start", "args": (trainer, model)},
          {"name": "on_fit_start"},
          {
              "name": "zero_grad",
              **(
                  {}
                  if _TORCH_GREATER_EQUAL_2_0
                  else {"kwargs": {"set_to_none": True}}
              ),
          },
          {
              "name": "Callback.on_sanity_check_start",
              "args": (trainer, model),
          },
          {"name": "val_dataloader"},
          {"name": "train", "args": (False,)},
          {"name": "on_validation_model_eval"},
          {
              "name": "Callback.on_validation_start",
              "args": (trainer, model),
          },
          {"name": "on_validation_start"},
          *model._eval_epoch(
              "validation",
              trainer,
              model,
              val_batches,
              "x",
              device=device,
          ),
          {
              "name": "Callback.on_validation_end",
              "args": (trainer, model),
          },
          {"name": "on_validation_end"},
          *(
              [{"name": "on_validation_model_train"}]
              if override_on_validation_model_train
              else []
          ),
          {
              "name": "Callback.on_sanity_check_end",
              "args": (trainer, model),
          },
          {"name": "train_dataloader"},
          {"name": "Callback.on_train_start", "args": (trainer, model)},
          {"name": "on_train_start"},
          {
              "name": "Callback.on_train_epoch_start",
              "args": (trainer, model),
          },
          {"name": "on_train_epoch_start"},
          *model._train_batch(
              trainer, model, train_batches, device=device, **kwargs
          ),
          {
              "name": "zero_grad",
              **(
                  {}
                  if _TORCH_GREATER_EQUAL_2_0
                  else {"kwargs": {"set_to_none": True}}
              ),
          },
          {"name": "on_validation_model_zero_grad"},
          {"name": "train", "args": (False,)},
          {"name": "on_validation_model_eval"},
          {
              "name": "Callback.on_validation_start",
              "args": (trainer, model),
          },
          {"name": "on_validation_start"},
          *model._eval_epoch(
              "validation",
              trainer,
              model,
              val_batches,
              "x",
              device=device,
          ),
          {
              "name": "Callback.on_validation_end",
              "args": (trainer, model),
          },
          {"name": "on_validation_end"},
          *(
              [{"name": "on_validation_model_train"}]
              if override_on_validation_model_train
              else []
          ),
          {
              "name": "Callback.on_train_epoch_end",
              "args": (trainer, model),
          },
          {
              "name": "on_train_epoch_end"
          },  # before ModelCheckpoint because it's a "monitoring callback"
          # `ModelCheckpoint.save_checkpoint` is called here
          {"name": "Callback.state_dict"},
          {
              "name": "Callback.on_save_checkpoint",
              "args": (trainer, model, saved_ckpt),
          },
          {"name": "on_save_checkpoint", "args": (saved_ckpt,)},
          {"name": "Callback.on_train_end", "args": (trainer, model)},
          {"name": "on_train_end"},
          {"name": "Callback.on_fit_end", "args": (trainer, model)},
          {"name": "on_fit_end"},
          {
              "name": "Callback.teardown",
              "args": (trainer, model),
              "kwargs": {"stage": "fit"},
          },
          {"name": "teardown", "kwargs": {"stage": "fit"}},
      ]
      assert called == expected
  
imports: from functools import partial, update_wrapper
  from inspect import getmembers, isfunction
  from unittest import mock
  from unittest.mock import ANY, PropertyMock
  import pytest
  import torch
  from lightning.fabric.utilities.imports import _TORCH_GREATER_EQUAL_2_0
  from lightning.pytorch import Callback, LightningDataModule, LightningModule, Trainer, __version__
  from lightning.pytorch.demos.boring_classes import BoringDataModule, BoringModel, RandomDataset
  from lightning.pytorch.utilities.model_helpers import is_overridden
  from torch import Tensor
  from torch.utils.data import DataLoader
  from tests_pytorch.helpers.runif import RunIf
label_desc: Use image node_id 6 for calling a global function with example usage: test_trainer_model_hook_system_fit(override_on_validation_model_train, automatic_optimization, kwargs, tmpdir) and returns: dict, super