Skip to content

Fix ordering of Python callbacks.#11812

Merged
trivialfis merged 2 commits into
dmlc:masterfrom
trivialfis:fix-callback
Nov 17, 2025
Merged

Fix ordering of Python callbacks.#11812
trivialfis merged 2 commits into
dmlc:masterfrom
trivialfis:fix-callback

Conversation

@trivialfis

Copy link
Copy Markdown
Member

Close #11811

@trivialfis
trivialfis requested a review from Copilot November 17, 2025 14:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR fixes the ordering of Python callbacks by changing the internal storage from a set to an ordered list while maintaining deduplication. The fix ensures that callbacks are executed in the order they are provided to the training function.

  • Changed callback storage from set to list(dict.fromkeys()) to preserve insertion order
  • Added comprehensive test to verify callback execution order is maintained
  • Added Optional import for type hints in the test

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
python-package/xgboost/callback.py Changed CallbackContainer.__init__ to use list(dict.fromkeys(callbacks)) instead of set(callbacks) to preserve callback ordering while still removing duplicates
tests/python/test_callback.py Added Optional import and new test_preserve_order test that verifies callbacks are executed in the specified order using custom callback classes

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@trivialfis

Copy link
Copy Markdown
Member Author

cc @rongou

is_cv: bool = False,
) -> None:
self.callbacks = set(callbacks)
self.callbacks = list(dict.fromkeys(callbacks))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious, is dict.fromkeys() here just for removing duplicates? Why do we even allow duplicates in the callback list? IMO it should be better just throw an error when there are duplicates instead of silently removing them.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious, is dict.fromkeys() here just for removing duplicates?

Yes, it's just to remove duplicates.

I agree. I don't recall the exact case, but when I rewrote the callback interface years ago, some other parameter tuning methods unnecessarily appended their callbacks to a list repeatedly.

I can try to raise an error in the next major release, this patch is supposed to go into a patch release for bug fix only.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for explanation. When will this patch release be out?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's continue the discussion in the original thread #11811 (comment) .

@trivialfis
trivialfis merged commit 3a62712 into dmlc:master Nov 17, 2025
65 checks passed
@trivialfis
trivialfis deleted the fix-callback branch November 17, 2025 22:58
trivialfis added a commit to trivialfis/xgboost that referenced this pull request Nov 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Early stopping callback results in indeterministic behavior in distributed XGBoost training

4 participants