def test_checkpoint_callbacks_are_last(tmp_path):
    """Test that checkpoint callbacks always get moved to the end of the list, with preserved order."""
    checkpoint1 = ModelCheckpoint(tmp_path, monitor="foo")
    checkpoint2 = ModelCheckpoint(tmp_path, monitor="bar")
    model_summary = ModelSummary()
    early_stopping = EarlyStopping(monitor="foo")
    lr_monitor = LearningRateMonitor()
    progress_bar = TQDMProgressBar()

    # no model reference
    trainer = Trainer(callbacks=[checkpoint1, progress_bar, lr_monitor, model_summary, checkpoint2])
    assert trainer.callbacks == [
        progress_bar,
        lr_monitor,
        model_summary,
        checkpoint1,
        checkpoint2,
    ]

    # no model callbacks
    model = LightningModule()
    model.configure_callbacks = lambda: []
    trainer.strategy._lightning_module = model
    cb_connector = _CallbackConnector(trainer)
    cb_connector._attach_model_callbacks()
    assert trainer.callbacks == [
        progress_bar,
        lr_monitor,
        model_summary,
        checkpoint1,
        checkpoint2,
    ]

    # with model-specific callbacks that substitute ones in Trainer
    model = LightningModule()
    model.configure_callbacks = lambda: [checkpoint1, early_stopping, model_summary, checkpoint2]
    trainer = Trainer(callbacks=[progress_bar, lr_monitor, ModelCheckpoint(tmp_path)])
    trainer.strategy._lightning_module = model
    cb_connector = _CallbackConnector(trainer)
    cb_connector._attach_model_callbacks()
    assert trainer.callbacks == [
        progress_bar,
        lr_monitor,
        early_stopping,
        model_summary,
        checkpoint1,
        checkpoint2,
    ]

    # with tuner-specific callbacks that substitute ones in Trainer
    model = LightningModule()
    batch_size_finder = BatchSizeFinder()
    model.configure_callbacks = lambda: [checkpoint2, early_stopping, batch_size_finder, model_summary, checkpoint1]
    trainer = Trainer(callbacks=[progress_bar, lr_monitor])
    trainer.strategy._lightning_module = model
    cb_connector = _CallbackConnector(trainer)
    cb_connector._attach_model_callbacks()
    assert trainer.callbacks == [
        batch_size_finder,
        progress_bar,
        lr_monitor,
        early_stopping,
        model_summary,
        checkpoint2,
        checkpoint1,
    ]
Test that checkpoint callbacks always get moved to the end of the list, with preserved order.
tests/tests_pytorch/trainer/connectors/test_callback_connector.py