Skip to content

[python-package] Guard docstring assignments for python -OO compatibility#12093

Closed
PavelGuzenfeld wants to merge 2 commits intodmlc:masterfrom
thebandofficial:fix/python-oo-docstring-crash
Closed

[python-package] Guard docstring assignments for python -OO compatibility#12093
PavelGuzenfeld wants to merge 2 commits intodmlc:masterfrom
thebandofficial:fix/python-oo-docstring-crash

Conversation

@PavelGuzenfeld
Copy link
Copy Markdown
Contributor

Summary

Running XGBoost with python -OO (PYTHONOPTIMIZE=2) strips all docstrings,
making __doc__ attributes None. This causes an AttributeError crash at
import time:

File "xgboost/sklearn.py", line 1826
    fit.__doc__ = XGBModel.fit.__doc__.replace(
AttributeError: 'NoneType' object has no attribute 'replace'

This PR wraps each __doc__ assignment with a None check instead of removing
them, so documentation is fully preserved in normal mode and the crash is
avoided under -OO.

Why this approach (guard, not remove)

PR #12085 was correctly rejected —
it removed the assignments outright, which would have dropped method-level
docstrings for save_model, load_model, XGBClassifier.fit, and Dask wrappers
in normal Python runs.

This PR instead adds a one-line if __doc__ is not None: guard before each
assignment. The result:

Mode Before this PR After this PR
Normal python Docstrings work Docstrings identical, no change
python -O Docstrings work Docstrings identical, no change
python -OO ImportError crash No crash, no docstrings (expected)

Addressing maintainer concern from #8537

"adding checks to all those places, and having to run all the tests with this
additional option is infeasible" — @trivialfis

There are only 5 assignments across 2 files. Each fix is a single if guard.
No new tests needed — the fix is defensive by nature and cannot alter behavior in
normal mode (the guarded code is identical to the original).

Changes

  • python-package/xgboost/sklearn.py — guard save_model.__doc__, load_model.__doc__, and XGBClassifier.fit.__doc__
  • python-package/xgboost/dask/__init__.py — guard DaskXGBClassifier.predict_proba.__doc__ and DaskXGBRanker.fit.__doc__

Closes #8537

Under python -OO (PYTHONOPTIMIZE=2), all docstrings are stripped and
__doc__ attributes become None. This causes an AttributeError crash
at import time when XGBClassifier.fit tries to call .replace() on
None, and makes save_model/load_model display "None" as their
docstrings via f-string interpolation.

Guard each __doc__ assignment with a None check so that:
- Normal mode: docstrings are preserved identically to before
- python -OO mode: assignments are skipped, preventing the crash

Closes dmlc#8537
@RAMitchell
Copy link
Copy Markdown
Member

Why are there 2 PRs on this?

@RAMitchell RAMitchell closed this Mar 18, 2026
@PavelGuzenfeld
Copy link
Copy Markdown
Contributor Author

The two PRs address the same issue (#8537) but take different approaches:

#12085 is closed and superseded by #12093.

@PavelGuzenfeld
Copy link
Copy Markdown
Contributor Author

@RAMitchell Could you please reopen this PR? It was likely closed due to the confusion about the two PRs, but as clarified above, #12085 (the removed approach) is already closed and this one (#12093) is the corrected fix with a different approach.

The underlying issue (#8537) is still present — XGBoost crashes on import under python -OO. This PR adds minimal if __doc__ is not None: guards (5 lines across 2 files) to fix it.

@PavelGuzenfeld PavelGuzenfeld deleted the fix/python-oo-docstring-crash branch March 18, 2026 21:03
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.

XGBoost not working if executed with python -OO

2 participants