Make ShapeConfig strict with slots=True#2553
Make ShapeConfig strict with slots=True#2553hujc7 wants to merge 1 commit intonewton-physics:mainfrom
Conversation
Plain @DataClass types silently accept writes to undeclared attribute names, creating dead attributes with no diagnostic. When a ShapeConfig field is renamed, existing cfg.old_name = value writes in downstream consumers keep running but become no-ops. Seen in practice in isaac-sim/IsaacLab#5289: PR newton-physics#1732 renamed ShapeConfig.contact_margin to gap. The downstream write builder.default_shape_cfg.contact_margin = 0.01 continued to run for weeks after the rename, created a dead attribute, and the intended 1 cm shape gap was never applied. Add slots=True to the @DataClass decorator on ShapeConfig so writes to unknown attribute names raise AttributeError at the write site. Future ShapeConfig renames will be loud for every consumer.
|
📝 WalkthroughWalkthroughThe Changes
Estimated code review effort🎯 1 (Trivial) | ⏱️ ~2 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 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.
Actionable comments posted: 1
🤖 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/sim/builder.py`:
- Line 213: You changed `@dataclass`(slots=True) on ShapeConfig which breaks
dynamic attribute writes; add a runtime deprecation phase and changelog entry:
emit a DeprecationWarning (from warnings.warn) when ShapeConfig is instantiated
(or on first attribute assignment) explaining that dynamic ad-hoc attributes
will be disallowed and advising users to migrate their ad-hoc data into a
dedicated dict/explicit fields or to subclass/compose a wrapper that holds extra
attributes; include a maintainer-approved explicit exception path if you want
immediate hard-fail (raise AttributeError with the same migration text) and
document which behavior is chosen. Then add an entry in CHANGELOG.md under
[Unreleased] (Deprecated/Changed) mentioning ShapeConfig, the slots=True
behavioral break, the deprecation timeline (when it will be removed or when
hard-fail applies), and concrete migration examples (use explicit fields,
.metadata dict, or subclassing) so users can update their code.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: 3b7550b9-1f04-4ec6-a9f4-e7f54ca24fa9
📒 Files selected for processing (1)
newton/_src/sim/builder.py
| args: list[dict[str, Any]] # Per-actuator array params (scalar params in dict key) | ||
|
|
||
| @dataclass | ||
| @dataclass(slots=True) |
There was a problem hiding this comment.
Add deprecation + changelog path for this behavioral break
slots=True intentionally breaks dynamic attribute writes on ShapeConfig (now AttributeError). Please add a deprecation phase (or explicit maintainer-approved exception) and a [Unreleased] CHANGELOG entry with migration guidance for users who previously attached ad-hoc attributes.
As per coding guidelines: “newton/!(tests)/**/*.py: Breaking changes require a deprecation first.” and “**: Check that any user-facing change includes a corresponding entry in CHANGELOG.md under the [Unreleased] section … For Deprecated, Changed, and Removed entries, verify the entry includes migration guidance…”.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@newton/_src/sim/builder.py` at line 213, You changed `@dataclass`(slots=True)
on ShapeConfig which breaks dynamic attribute writes; add a runtime deprecation
phase and changelog entry: emit a DeprecationWarning (from warnings.warn) when
ShapeConfig is instantiated (or on first attribute assignment) explaining that
dynamic ad-hoc attributes will be disallowed and advising users to migrate their
ad-hoc data into a dedicated dict/explicit fields or to subclass/compose a
wrapper that holds extra attributes; include a maintainer-approved explicit
exception path if you want immediate hard-fail (raise AttributeError with the
same migration text) and document which behavior is chosen. Then add an entry in
CHANGELOG.md under [Unreleased] (Deprecated/Changed) mentioning ShapeConfig, the
slots=True behavioral break, the deprecation timeline (when it will be removed
or when hard-fail applies), and concrete migration examples (use explicit
fields, .metadata dict, or subclassing) so users can update their code.
Description
ModelBuilder.ShapeConfigis a plain@dataclass. Python silently accepts writes to undeclared attribute names on such classes, so a downstreamcfg.old_name = valuebecomes a dead no-op whenold_nameis renamed upstream.Seen in practice in isaac-sim/IsaacLab#5289: PR #1732 renamed
ShapeConfig.contact_margin→gap, and Isaac Lab's stale writebuilder.default_shape_cfg.contact_margin = 0.01continued to run for weeks after the pin bump, created a dead attribute, and the intended 1 cm shape gap was never applied.Change
Add
slots=Trueto the@dataclassdecorator onShapeConfig. Writes to unknown attribute names now raiseAttributeErrorat the write site, so any futureShapeConfigrename is loud for every consumer.Scope is intentionally narrow to
ShapeConfig. Happy to apply the same toActuatorEntry,CustomAttribute,CustomFrequencyin a follow-up if the approach is accepted.Compatibility
Sanity-checked by applying the change to an installed Newton copy and verifying:
cfg.gap,cfg.margin,cfg.density).cfg.contact_margin = 0.01(the IsaacLab#5289 case) raisesAttributeError: 'ShapeConfig' object has no attribute 'contact_margin'.ShapeConfig.copy(),dataclasses.replace, andpickleround-trips all continue to work.default_shape_cfg.<field> = ...writes in Newton's test suite (30 files) — every write targets a declared field.newton/tests/test_mesh_backface.py::TestHeightfieldPrismSteepAndRotated(4 tests exercisingdefault_shape_cfg.mu/margin/gap) — all pass.Breaking for any out-of-tree user that attaches custom attributes to
ShapeConfig; those writes were already dead when they used typo'd names, this just makes them loud.Newton Migration Guide
docs/migration.rstis up-to date(No migration guide entry added; the change does not rename or remove any public API. Happy to add a note if maintainers prefer.)
Before your PR is "Ready for review"
ShapeConfig-touching tests continue to pass)pre-commit run -aSummary by CodeRabbit