Fix State.assign for namespaced extended and custom attributes#2487
Fix State.assign for namespaced extended and custom attributes#2487jsw7460 wants to merge 4 commits intonewton-physics:mainfrom
State.assign for namespaced extended and custom attributes#2487Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughRefactors State.assign() to copy wp.array attributes in two phases: top-level arrays and namespaced arrays via Model.AttributeNamespace containers, adding a helper to perform namespace-prefixed array copying and raising ValueError on per-namespace array-allocation mismatches. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
newton/_src/sim/state.py (1)
183-209: LGTM — namespaced extended-attr branch mirrors the top-level semantics correctly.Branch analysis:
- Both namespaces missing → skip ✓
- One namespace missing while the other holds a
wp.array→val_*becomesNonevia the conditionalgetattr, and the subsequentval_self is None or not array_self/val_other is None or not array_otherchecks raise with the qualified"ns.attr"name ✓- Both namespaces present, neither has the attribute allocated →
val_self/val_otherbothNone, skipped bynot array_self and not array_other✓- Both present and allocated →
val_self.assign(val_other)✓Optional nit: the top-level loop and this block share the same presence/mismatch/assign pattern. If a third call site ever appears (or recursion is introduced, as noted in the PR description), extracting a small
_assign_array(name, val_self, val_other)helper would DRY this up. Not required for this PR.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@newton/_src/sim/state.py` around lines 183 - 209, The namespaced extended-attribute block duplicates the presence/mismatch/assign pattern used at top-level; optionally extract a small helper (e.g., _assign_array(qualified_name, val_self, val_other)) to encapsulate the checks and assignment so both the top-level loop and the EXTENDED_ATTRIBUTES loop call the same logic (replace the repeated checks that compute array_self/array_other, raise the two ValueError messages with the qualified name, and call val_self.assign(val_other)).newton/tests/test_state_assign.py (1)
35-64: Tests cover the three main branches — nice.A couple of optional additions that would harden regression coverage without much cost:
- Assert the raised
ValueErrormessage contains the qualified name (e.g."mujoco.qfrc_actuator") so a future refactor that drops the namespace prefix from the error message is caught:with self.assertRaisesRegex(ValueError, r"mujoco\.qfrc_actuator"): state_0.assign(state_1)- A positive no-op test where both states have the
mujoconamespace butqfrc_actuatorwas never requested (i.e., the attribute isNoneon both sides) would lock in the “skip silently” branch at lines 199-200.Both are nice-to-have, not blocking.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@newton/tests/test_state_assign.py` around lines 35 - 64, Update TestStateAssignNamespacedAttributes to tighten assertions and add a no-op branch test: for the two tests that expect ValueError when a namespaced attribute is missing, replace assertRaises with self.assertRaisesRegex(ValueError, r"mujoco\.qfrc_actuator") to ensure the error message mentions the qualified name when calling state_0.assign(state_1); and add a new test that constructs state_0 and state_1 where both have a mujoco namespace but qfrc_actuator is None on both sides, then call state_0.assign(state_1) and assert no exception (a successful no-op) to cover the "skip silently" branch in the assign implementation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@newton/_src/sim/state.py`:
- Around line 183-209: The namespaced extended-attribute block duplicates the
presence/mismatch/assign pattern used at top-level; optionally extract a small
helper (e.g., _assign_array(qualified_name, val_self, val_other)) to encapsulate
the checks and assignment so both the top-level loop and the EXTENDED_ATTRIBUTES
loop call the same logic (replace the repeated checks that compute
array_self/array_other, raise the two ValueError messages with the qualified
name, and call val_self.assign(val_other)).
In `@newton/tests/test_state_assign.py`:
- Around line 35-64: Update TestStateAssignNamespacedAttributes to tighten
assertions and add a no-op branch test: for the two tests that expect ValueError
when a namespaced attribute is missing, replace assertRaises with
self.assertRaisesRegex(ValueError, r"mujoco\.qfrc_actuator") to ensure the error
message mentions the qualified name when calling state_0.assign(state_1); and
add a new test that constructs state_0 and state_1 where both have a mujoco
namespace but qfrc_actuator is None on both sides, then call
state_0.assign(state_1) and assert no exception (a successful no-op) to cover
the "skip silently" branch in the assign implementation.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: 5ec6a0c5-40c9-467e-aa81-f82f0466fc2f
📒 Files selected for processing (3)
CHANGELOG.mdnewton/_src/sim/state.pynewton/tests/test_state_assign.py
camevor
left a comment
There was a problem hiding this comment.
Thanks for spotting and fixing this, @jsw7460! Since the namespace issue also affects custom attributes (to an even larger extent), it would make sense to handle those in the same way. Discovering AttributeNamespace entries on the state object would cover both cases in one pass.
state.mujoco.* arrays (e.g. qfrc_actuator) were skipped because the top-level loop only matches wp.array instances, and namespaces are not arrays. Walk EXTENDED_ATTRIBUTES for "namespace:attr" entries after the top-level loop with the same presence and mismatch semantics.
Address review feedback: unify handling of extended and custom namespaced attributes via runtime AttributeNamespace discovery.Custom attributes added via ModelBuilder.add_custom_attribute are now copied by State.assign as well. Extend tests to cover custom namespaced attributes, including multiple attributes within a namespace and per-attribute presence mismatch.
777d9c2 to
11ce9cf
Compare
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
State.assign for namespaced extended and custom attributes
Signed-off-by: camevor <camevor@nvidia.com>
Description
State.assignskipswp.arrayattributes nested under attribute namespaces (e.g.state.mujoco.qfrc_actuator). The top-level loop only checksisinstance(val, wp.array)on__dict__entries, so namespace containers are skipped and never descended into. Afterstate_0.assign(state_1),state_0.mujoco.qfrc_actuatoris still zero.Fix: after the top-level loop, walk
EXTENDED_ATTRIBUTESfor"namespace:attr"entries and apply the same presence/mismatch checks.Checklist
CHANGELOG.mdhas been updated (if user-facing change)Test plan
uv run --extra dev -m newton.tests -k test_state_assign
Bug fix
Steps to reproduce:
mujoco:qfrc_actuatoron a model and stepSolverMuJoCosostate_1.mujoco.qfrc_actuatoris populated.state_0.assign(state_1)(the patternState.assign's docstring recommends for odd-substep CUDA-graph loops).state_0.mujoco.qfrc_actuator: values are still the zero-initialized array.Minimal reproduction:
See test_state_assign.py
Note: I followed the current
"namespace:attr"convention inEXTENDED_ATTRIBUTES.If deeper nesting is needed in the future, let me know and I'll switch to a recursive approach.
Summary by CodeRabbit
Bug Fixes
Tests
Refactor