Skip to content

Remove return value from solver step()#1968

Merged
preist-nvidia merged 5 commits into
newton-physics:mainfrom
preist-nvidia:preist/remove-step-return-value
Mar 9, 2026
Merged

Remove return value from solver step()#1968
preist-nvidia merged 5 commits into
newton-physics:mainfrom
preist-nvidia:preist/remove-step-return-value

Conversation

@preist-nvidia

@preist-nvidia preist-nvidia commented Mar 6, 2026

Copy link
Copy Markdown
Member

Description

The step() method on all solvers writes results into state_out in-place. Returning state_out was redundant — no callers use the return value.

The -> State | None return type annotation on the base class was likely introduced incorrectly in #1749. This PR removes it, along with the return state_out statements in the xpbd, featherstone, and mujoco implementations to make all solvers consistent. The vbd, style3d, semi_implicit, and implicit_mpm solvers already had no return statement.

Checklist

  • New or existing tests cover these changes
  • The documentation is up to date with these changes
  • CHANGELOG.md has been updated (if user-facing change)

Test plan

Internal cleanup with no behavior change. Full test suite passes:

uv run --extra dev -m newton.tests                                                                                                          
                                                                                                                                              
Ran 2448 tests in 712.587s — OK (skipped=147)

Summary by CodeRabbit

  • Bug Fixes / Refactor
    • Solver step methods now update state in-place and no longer return the updated state object.
    • Model-change notification methods explicitly indicate no return value.
    • Public solver signatures unified to explicitly declare no return, clarifying API behavior and reducing caller ambiguity.

The step() method wrote results into state_out in-place; returning it
was redundant and no callers used the value. Remove the return type
annotation from the base class and the return statements from the
xpbd, featherstone, and mujoco implementations.
@preist-nvidia preist-nvidia self-assigned this Mar 6, 2026
@coderabbitai

coderabbitai Bot commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: d55c9edb-e4f4-417e-9bd1-eb973b367145

📥 Commits

Reviewing files that changed from the base of the PR and between ef9ec5e and e129a4f.

📒 Files selected for processing (1)
  • newton/_src/solvers/solver.py

📝 Walkthrough

Walkthrough

Added explicit return type annotations (-> None) to many solver public methods and removed explicit return state_out from several step implementations; an implicit_mpm solver gained step and notify_model_changed method stubs.

Changes

Cohort / File(s) Summary
Core Solver Base
newton/_src/solvers/solver.py
Added explicit -> None return annotations for integrate_bodies, integrate_particles, and notify_model_changed; changed SolverBase.step return annotation to -> None (was `State
Featherstone Solver
newton/_src/solvers/featherstone/solver_featherstone.py
notify_model_changed and step now annotated -> None; step no longer returns state_out (now relies on in-place mutation).
MuJoCo Solver
newton/_src/solvers/mujoco/solver_mujoco.py
notify_model_changed and step now annotated -> None; explicit return state_out removed from step.
XPBD Solver
newton/_src/solvers/xpbd/solver_xpbd.py
notify_model_changed and step annotated -> None; removed early return state_out at end of step.
Implicit MPM Solver (new/updated)
newton/_src/solvers/implicit_mpm/solver_implicit_mpm.py
Added step(...) -> None and notify_model_changed(...) -> None method stubs / annotations.
Semi-Implicit / Style3D / VBD Solvers
newton/_src/solvers/semi_implicit/solver_semi_implicit.py, newton/_src/solvers/style3d/solver_style3d.py, newton/_src/solvers/vbd/solver_vbd.py
Added explicit -> None return annotations to step methods; no other logic changes.

Sequence Diagram(s)

(omitted)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • nvtw
  • Kenny-Vilella
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 52.38% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Remove return value from solver step()' directly and clearly describes the main change: eliminating return values from step() methods across solver implementations.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov

codecov Bot commented Mar 6, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai Bot 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
newton/_src/solvers/solver.py (1)

272-285: ⚠️ Potential issue | 🟠 Major

Don't remove the step() return contract without a deprecation window.

This changes the public SolverBase.step() API from State | None to an implicit no-return contract. Even if in-repo callers ignore the result, external users and typed integrations can still be doing state = solver.step(...), so this is a breaking change. Please keep the old contract for this release and deprecate the return value first, then remove it in a later release with explicit migration guidance. As per coding guidelines, newton/**/*.py: Breaking changes require a deprecation first. Do not remove or rename public API symbols without deprecating them in a prior release.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@newton/_src/solvers/solver.py` around lines 272 - 285, Restore the original
return contract by changing the step signature back to return State | None (i.e.
def step(self, ... ) -> State | None) and update the docstring to mark the
returned State as deprecated (include a short deprecation note and migration
guidance), keep the current NotImplementedError in the base implementation so
subclasses still must implement it, and add a TODO/deprecation comment that the
return value will be removed in a future release so callers can be migrated
before the breaking change; reference the step method on SolverBase (step) so
reviewers can find and verify the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@newton/_src/solvers/solver.py`:
- Around line 272-285: Restore the original return contract by changing the step
signature back to return State | None (i.e. def step(self, ... ) -> State |
None) and update the docstring to mark the returned State as deprecated (include
a short deprecation note and migration guidance), keep the current
NotImplementedError in the base implementation so subclasses still must
implement it, and add a TODO/deprecation comment that the return value will be
removed in a future release so callers can be migrated before the breaking
change; reference the step method on SolverBase (step) so reviewers can find and
verify the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 120d2496-e5dd-41d2-8c18-cd591bd43a05

📥 Commits

Reviewing files that changed from the base of the PR and between d0eb7f7 and e7cb4a3.

📒 Files selected for processing (4)
  • newton/_src/solvers/featherstone/solver_featherstone.py
  • newton/_src/solvers/mujoco/solver_mujoco.py
  • newton/_src/solvers/solver.py
  • newton/_src/solvers/xpbd/solver_xpbd.py
💤 Files with no reviewable changes (3)
  • newton/_src/solvers/xpbd/solver_xpbd.py
  • newton/_src/solvers/featherstone/solver_featherstone.py
  • newton/_src/solvers/mujoco/solver_mujoco.py

Comment thread newton/_src/solvers/solver.py Outdated

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
newton/_src/solvers/featherstone/solver_featherstone.py (1)

324-331: ⚠️ Potential issue | 🟠 Major

step() return removal needs a deprecation path.

Changing this public method from returning state_out to returning None will break downstream code that does state = solver.step(...). If the API is being tightened, please deprecate the old behavior for a release first and add migration guidance before removing the return value outright.

As per coding guidelines, newton/**/*.py: Breaking changes require a deprecation first. Do not remove or rename public API symbols without deprecating them in a prior release.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@newton/_src/solvers/featherstone/solver_featherstone.py` around lines 324 -
331, The public method step(self, state_in: State, state_out: State, control:
Control, contacts: Contacts, dt: float) was changed to return None which breaks
callers expecting a returned state; restore backward compatibility by retaining
the original return of state_out while emitting a DeprecationWarning (via
warnings.warn(..., DeprecationWarning)) and updating the step docstring to state
the return will be removed in a future release, then schedule removal in a
subsequent release; locate the method named step in class SolverFeatherstone (in
solver_featherstone.py), add the warnings.warn call inside the method before
returning state_out, and document the deprecation and migration guidance in the
docstring.
🧹 Nitpick comments (1)
newton/_src/solvers/featherstone/solver_featherstone.py (1)

324-331: Match the override's parameter types to the base contract.

The override at solver_featherstone.py:324 narrows control and contacts to non-optional types, but the implementation handles None at lines 344 and 447. The base class SolverBase.step (line 272 in solver.py) declares these as Control | None and Contacts | None, per PEP 604 conventions. Update the signature to accept the same parameter types:

     def step(
         self,
         state_in: State,
         state_out: State,
-        control: Control,
-        contacts: Contacts,
+        control: Control | None,
+        contacts: Contacts | None,
         dt: float,
     ) -> None:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@newton/_src/solvers/featherstone/solver_featherstone.py` around lines 324 -
331, The step override in solver_featherstone.py narrows parameter types for
control and contacts but the implementation accepts None; change the signature
of SolverFeatherstone.step to match the base contract by typing control and
contacts as optional (Control | None and Contacts | None) so it matches
SolverBase.step; update only the method signature in def step(...) to use these
union types (PEP 604) to resolve the mismatch.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@newton/_src/solvers/style3d/solver_style3d.py`:
- Line 167: The step method declares an unused parameter control which triggers
ARG002; explicitly consume it or silence the linter without changing the API:
inside the step(self, state_in: State, state_out: State, control: Control,
contacts: Contacts, dt: float) implementation, either add a statement to consume
the parameter (e.g., del control) or add a narrow noqa comment on the parameter
usage to suppress ARG002, leaving the function signature (step) unchanged.

In `@newton/_src/solvers/xpbd/solver_xpbd.py`:
- Around line 249-250: Preserve backward compatibility by temporarily keeping
SolverXPBD.step(...) returning the passed-in state_out while marking that return
as deprecated: update the method to still return state_out, add a runtime
DeprecationWarning (via warnings.warn) and update the step docstring to state
the return will be removed and callers should use the state_out argument; also
add an entry under CHANGELOG.md [Unreleased] explaining the deprecation with
migration guidance ("use the passed-in state_out instead of the return value");
apply the same deprecation pattern to the other affected occurrence(s)
referenced (the similar step implementation around the second mention) so all
public API callers are warned consistently.

---

Outside diff comments:
In `@newton/_src/solvers/featherstone/solver_featherstone.py`:
- Around line 324-331: The public method step(self, state_in: State, state_out:
State, control: Control, contacts: Contacts, dt: float) was changed to return
None which breaks callers expecting a returned state; restore backward
compatibility by retaining the original return of state_out while emitting a
DeprecationWarning (via warnings.warn(..., DeprecationWarning)) and updating the
step docstring to state the return will be removed in a future release, then
schedule removal in a subsequent release; locate the method named step in class
SolverFeatherstone (in solver_featherstone.py), add the warnings.warn call
inside the method before returning state_out, and document the deprecation and
migration guidance in the docstring.

---

Nitpick comments:
In `@newton/_src/solvers/featherstone/solver_featherstone.py`:
- Around line 324-331: The step override in solver_featherstone.py narrows
parameter types for control and contacts but the implementation accepts None;
change the signature of SolverFeatherstone.step to match the base contract by
typing control and contacts as optional (Control | None and Contacts | None) so
it matches SolverBase.step; update only the method signature in def step(...) to
use these union types (PEP 604) to resolve the mismatch.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 558ab94e-e34d-46be-8902-b7b79c9ac322

📥 Commits

Reviewing files that changed from the base of the PR and between e7cb4a3 and ef9ec5e.

📒 Files selected for processing (8)
  • newton/_src/solvers/featherstone/solver_featherstone.py
  • newton/_src/solvers/implicit_mpm/solver_implicit_mpm.py
  • newton/_src/solvers/mujoco/solver_mujoco.py
  • newton/_src/solvers/semi_implicit/solver_semi_implicit.py
  • newton/_src/solvers/solver.py
  • newton/_src/solvers/style3d/solver_style3d.py
  • newton/_src/solvers/vbd/solver_vbd.py
  • newton/_src/solvers/xpbd/solver_xpbd.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • newton/_src/solvers/solver.py
  • newton/_src/solvers/mujoco/solver_mujoco.py

Comment thread newton/_src/solvers/style3d/solver_style3d.py
Comment thread newton/_src/solvers/xpbd/solver_xpbd.py

@adenzler-nvidia adenzler-nvidia left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good — all solver step() and notify_model_changed() signatures consistently annotated with -> None, and the three stale return state_out statements removed.

@adenzler-nvidia adenzler-nvidia left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good — all solver step() and notify_model_changed() signatures consistently annotated with -> None, and the three stale return state_out statements removed.

@preist-nvidia preist-nvidia enabled auto-merge March 9, 2026 16:46
@preist-nvidia preist-nvidia added this pull request to the merge queue Mar 9, 2026
Merged via the queue into newton-physics:main with commit 774d3e5 Mar 9, 2026
22 checks passed
@github-project-automation github-project-automation Bot moved this from In Progress to Done in Newton Roadmap Mar 9, 2026
adenzler-nvidia pushed a commit to adenzler-nvidia/newton that referenced this pull request Mar 9, 2026
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
mmacklin pushed a commit to mmacklin/newton that referenced this pull request Apr 7, 2026
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants