Skip to content

[python-package] Fix python -OO crash by guarding __doc__ assignments#12094

Merged
RAMitchell merged 1 commit intodmlc:masterfrom
thebandofficial:fix/remove-fit-doc
Mar 18, 2026
Merged

[python-package] Fix python -OO crash by guarding __doc__ assignments#12094
RAMitchell merged 1 commit intodmlc:masterfrom
thebandofficial:fix/remove-fit-doc

Conversation

@PavelGuzenfeld
Copy link
Copy Markdown
Contributor

Summary

Fixes an import crash when running python -OO (or PYTHONOPTIMIZE=2) by guarding all runtime __doc__ assignments against None.

Under -OO, Python strips all docstrings so __doc__ is None. The existing code:

  • Uses f-strings interpolating Booster.save_model.__doc__ / Booster.load_model.__doc__ (produces None in output)
  • Asserts XGBModel.fit.__doc__ is not None then calls .replace() on it (crashes with AssertionError)
  • Copies __doc__ from sklearn wrappers in dask (assigns None — harmless but pointless)

This PR wraps each __doc__ assignment with if source.__doc__ is not None: so:

  • Under -OO: assignments are silently skipped, no crash
  • Under normal Python: docstrings work exactly as before

Closes #8537

Supersedes #12085 (reworked based on review feedback — previous approach removed docstrings entirely, this one preserves them)

Test plan

  • python -OO -c "import xgboost" no longer crashes
  • Normal python -c "import xgboost; help(xgboost.XGBClassifier.fit)" still shows full docstrings

Under `python -OO`, docstrings are stripped and `__doc__` is None.
Code that reads `__doc__` from one object to copy or mutate it for
another would crash with an AttributeError (e.g. calling `.replace()`
on None).

Wrap each `__doc__` assignment with a `if source.__doc__ is not None`
guard so the assignment is simply skipped under -OO, while preserving
full docstring behavior under normal Python.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes an import-time crash when running XGBoost under python -OO / PYTHONOPTIMIZE=2 by ensuring runtime __doc__ reassignments are skipped when the source docstring is None (as happens when docstrings are stripped).

Changes:

  • Guard save_model / load_model docstring copying from Booster against None.
  • Guard XGBClassifier.fit.__doc__ rewriting (previously relied on an assert and .replace()).
  • Guard docstring copying for Dask wrappers (predict_proba, fit) against None.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
python-package/xgboost/sklearn.py Adds None checks around Booster.*.__doc__ copies and XGBModel.fit.__doc__-based rewrite to prevent -OO import crashes.
python-package/xgboost/dask/init.py Adds None checks for docstring copying from sklearn wrappers to avoid -OO issues and no-op assignments.

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

Comment on lines +1125 to +1126
if Booster.save_model.__doc__ is not None:
save_model.__doc__ = f"""{Booster.save_model.__doc__}"""
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good suggestion — added in d2f0f0e.

@PavelGuzenfeld
Copy link
Copy Markdown
Contributor Author

Added a regression test in tests/python/test_basic.py — runs python -OO -c "import xgboost" in a subprocess to guard against future __doc__-related import crashes.

@RAMitchell RAMitchell merged commit dc2a1bf into dmlc:master Mar 18, 2026
84 checks passed
@PavelGuzenfeld PavelGuzenfeld deleted the fix/remove-fit-doc branch March 18, 2026 21:03
PavelGuzenfeld added a commit to PavelGuzenfeld/xgboost that referenced this pull request Mar 19, 2026
Add section documenting 3 merged PRs (dmlc#12087, dmlc#12089, dmlc#12094),
1 open PR (dmlc#12086), and 3 closed/superseded PRs.
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

3 participants