GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — FIX return self from partial_fit of MultiOutputRegressor and BernoulliRBM by lau0708 · Pull Request #35350 · scikit-learn/scikit-learn

Conversation

@lau0708

@lau0708 lau0708 commented Nov 8, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

Reference Issues/PRs

Fixes #35347

What does this implement/fix? Explain your changes.

partial_fit is documented to return self for both of these estimators, and neither did. In both cases the override dropped the return that the implementation it mirrors already has, so the documented chaining idiom est.partial_fit(X, y).predict(X) fails with AttributeError: 'NoneType' object has no attribute 'predict'.

  • MultiOutputRegressor.partial_fit (sklearn/multioutput.py:430) calls super().partial_fit(...) and discards the result. Its sibling MultiOutputClassifier inherits _MultiOutputEstimator.partial_fit (sklearn/multioutput.py:203), which does return self — the two siblings in the same hierarchy disagree, and only the classifier gets it right.
  • BernoulliRBM.partial_fit (sklearn/neural_network/_rbm.py:310) ends with self._fit(...) and falls off the end of the function, while BernoulliRBM.fit (sklearn/neural_network/_rbm.py:437) ends with return self.

Both docstrings have a Returns section promising a fitted instance, so this makes the code match the documented contract. Production diff is 2 lines; the rest is one non-regression test per estimator.

Deliberately out of scope:

  • partial_fit of other estimators — I scanned all 24 partial_fit definitions in the code base against their documented Returns section and these are the only two that disagree.
  • The AttributeError vs NotFittedError question for chaining on an unfitted estimator — unrelated.

Testing

Red on clean main @ 6e37063 (source build, macOS, Python 3.13.12), the two new tests fail with assert None is <MultiOutputRegressor instance> and assert None is <BernoulliRBM instance>; the same script prints:

MOR.partial_fit -> None
MOC.partial_fit -> True
RBM.partial_fit -> None
RBM.fit -> True

Green on the branch. Both new tests keep a control assertion that passes before and after the change (MultiOutputClassifier.partial_fit(...) is clf and BernoulliRBM.fit(...) is rbm), so the red is attributable to the missing return rather than to the test scaffolding.

Command base branch
pytest sklearn/tests/test_multioutput.py sklearn/neural_network/tests/test_rbm.py 96 passed 98 passed
pytest sklearn/tests/test_common.py -k "BernoulliRBM or MultiOutputRegressor or MultiOutputClassifier" — 109 passed, 15 skipped, 2 xfailed
ruff check + ruff format --check (0.12.2, as pinned in .pre-commit-config.yaml) — clean

Changelog fragment added under many-modules, since the fix touches both sklearn.multioutput and sklearn.neural_network; happy to split it per module or move it if you prefer.

Introduce yourself

I use scikit-learn mainly for tabular modeling. I was reading the partial_fit docstrings while working with incremental training and noticed that the Returns section promised an instance that two implementations never returned; the asymmetry with MultiOutputClassifier / BernoulliRBM.fit looked like an oversight rather than a deliberate choice.

AI usage disclosure

I used AI assistance for:

  • Code generation (e.g., when writing an implementation or fixing a bug)
  • Test/benchmark generation
  • Research and understanding

Everything reported above (red/green, control assertions, test counts, lint) I ran and checked locally myself.

Any other comments?

The issue was triaged after the earlier attempt (#35349) had already been auto-closed by the bot for being opened while the issue still carried Needs Triage; this PR is opened after triage, as the contributing guide asks.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@lau0708
FIX return self from partial_fit of MultiOutputRegressor and Bernoull…
fce313a
…iRBM

Both implementations documented `Returns self` but returned None, so the
documented chaining idiom (`est.partial_fit(X, y).predict(X)`) raised
AttributeError. MultiOutputClassifier and BernoulliRBM.fit already return
the estimator, which made the two outliers hard to spot.

Non-regression tests assert the return value and keep a control assertion
on the sibling that already behaved correctly (scikit-learngh-35347).
@github-actions github-actions Bot added the module:neural_network label Nov 8, 2026
@lau0708
DOC add changelog entry for partial_fit return value fix
4416287
@github-actions github-actions Bot added the size/S label Nov 8, 2026
@github-actions

github-actions Bot commented Nov 8, 2026

Copy link
Copy Markdown

Thank you for opening your first pull request to scikit-learn! 🎉

To help get your contribution reviewed, please make sure that:

  • You have filled out the pull request template.

  • The pull request addresses an existing issue that is ready for contribution (e.g. not tagged as 'Needs Triage', 'Needs Decision', ...). If you are proposing a new feature, please open an issue to discuss it first.

  • There are no other open pull requests already targeting the same issue.

  • You have followed the pull request checklist. In particular, linting and tests should pass.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@github-actions github-actions Bot added size/M and removed size/S labels Nov 8, 2026
@Yi-111-a Yi-111-a mentioned this pull request Nov 8, 2026
fix: return self from FrozenEstimator.set_params #35346
Merged
cakedev0
cakedev0 reviewed Nov 9, 2026
View reviewed changes

@cakedev0 cakedev0 left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Overall LGTM, but let's be a bit less verbose.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread doc/whats_new/upcoming_changes/many-modules/35350.fix.rst Outdated
Comment on lines +3 to +8
docstrings state, instead of `None`. This restores the documented chaining
idiom, so that e.g. `est.partial_fit(X, y).predict(X)` no longer raises
`AttributeError`. Both implementations now behave like their sibling
:meth:`multioutput.MultiOutputClassifier.partial_fit` and
:meth:`neural_network.BernoulliRBM.fit`.
By :user:`lau0708`.

@cakedev0 cakedev0 Nov 9, 2026

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Too much details IMO.

Suggested change
docstrings state, instead of `None`. This restores the documented chaining
idiom, so that e.g. `est.partial_fit(X, y).predict(X)` no longer raises
`AttributeError`. Both implementations now behave like their sibling
:meth:`multioutput.MultiOutputClassifier.partial_fit` and
:meth:`neural_network.BernoulliRBM.fit`.
By :user:`lau0708`.
docstrings state, instead of `None`.
By :user:`lau0708`.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@lau0708 lau0708 Nov 10, 2026

Copy link
Copy Markdown
Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Agreed, trimmed. It is now just the two-line summary of the behaviour change — dropped the chaining / AttributeError elaboration. (f27c9ec)

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread sklearn/neural_network/tests/test_rbm.py Outdated
assert_array_equal(X, Xdigits)


def test_partial_fit_returns_self():

@cakedev0 cakedev0 Nov 9, 2026

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Maybe you could just add a small assert in an existing partial fit test instead of a new dedicated test?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

lucyleeow reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

@lau0708 lau0708 Nov 10, 2026

Copy link
Copy Markdown
Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Done — moved the assert rbm.partial_fit(batch) is rbm into the existing test_partial_fit loop and dropped the dedicated test. Checked that the assert still bites: removing return self gives assert None is BernoulliRBM(...). (b17ae24)

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread sklearn/tests/test_multioutput.py Outdated
assert not hasattr(MultiOutputRegressor(Lasso), "partial_fit")


def test_partial_fit_returns_self():

@cakedev0 cakedev0 Nov 9, 2026

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Maybe you could just add a small assert in an existing partial fit test instead of a new dedicated test?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@lau0708 lau0708 Nov 10, 2026

Copy link
Copy Markdown
Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Same here — the assert now sits in test_multi_target_regression_partial_fit on the second partial_fit call, and test_partial_fit_returns_self is gone. (b17ae24)

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
lau0708 added 2 commits November 10, 2026 22:04
@lau0708
DOC shorten changelog entry for partial_fit return value fix
f27c9ec
@lau0708
TST assert return self inside existing partial_fit tests
b17ae24
@github-actions github-actions Bot added size/S and removed size/M labels Nov 10, 2026
@lau0708

lau0708 commented Nov 10, 2026

Copy link
Copy Markdown
Author

Thanks for the review — all three points are addressed in b17ae24. Heads-up: head moved from 4416287, so the diff you looked at has shifted.

  • Changelog cut to 4 lines; it no longer restates the chaining idiom.
  • The two dedicated test_*_returns_self tests are dropped. Each file now has a single assertion in its existing partial_fit test (inside the batch loop in test_partial_fit, which also covers the repeated-call path).

Re-checked that the assertions are load-bearing: with the two production changes reverted, they fail with assert None is BernoulliRBM(...) / assert None is MultiOutputRegressor(...); with them in place, test_rbm.py is 24 passed and test_multioutput.py 72 passed, and ruff check / ruff format --check (0.12.2) are clean on all four files.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

cakedev0
cakedev0 approved these changes Nov 10, 2026
View reviewed changes

@cakedev0 cakedev0 left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

LGTM.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@cakedev0 cakedev0 added Quick Review For PRs that are quick to review Waiting for Second Reviewer First reviewer is done, need a second one! labels Nov 10, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

1 more reviewer
@cakedev0 cakedev0 cakedev0 approved these changes
Reviewers whose approvals may not affect merge requirements

At least 1 approving review is required to merge this pull request.

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

module:neural_network Quick Review For PRs that are quick to review size/S Waiting for Second Reviewer First reviewer is done, need a second one!

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

BUG: partial_fit returns None in MultiOutputRegressor and BernoulliRBM, contradicting its documented Returns self

Uh oh!

There was an error while loading. Please reload this page.

2 participants

@lau0708 @cakedev0
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.