Skip to content

fix: clone forward list to prevent shared mutation across form subclasses (#1333)#1410

Merged
jpic merged 4 commits intoyourlabs:masterfrom
PurpleToti:master
Apr 28, 2026
Merged

fix: clone forward list to prevent shared mutation across form subclasses (#1333)#1410
jpic merged 4 commits intoyourlabs:masterfrom
PurpleToti:master

Conversation

@PurpleToti
Copy link
Copy Markdown

@PurpleToti PurpleToti commented Apr 27, 2026

Summary

Port and cleanup of #1358, fixing #1333.

Problem

WidgetMixin.forward is a mutable list. Because Django deep-copies widget instances from class-level field definitions rather than re-instantiating them, all form subclasses sharing a common base class reference the same list object. Any __init__ that appends to widget.forward silently mutates every sibling form instantiated from the same base.

Changes

src/dal/widgets.py

  • WidgetMixin.__init__: replace self.forward = forward or [] with list(forward) if forward else [] — always produces a fresh list, never shares the caller's reference.
  • WidgetMixin.__deepcopy__: new method that delegates to super().__deepcopy__() then re-copies .forward, so widget clones are also isolated.

test_project/tests/test_widgets.py

  • New ForwardCloningTest::test_forwards_are_cloned: two subclasses of a shared base form each append a different forward.Const; asserts each sees exactly one entry with the correct destination key, directly reproducing the original bug.

Difference from #1358

One minor simplification: list(forward).copy()list(forward) (the .copy() call is redundant since list() already copies).

Tested against

Django 5.2 and 6.0, Python 3.11–3.14. All existing tests pass.

Summary by CodeRabbit

  • Bug Fixes
    • Resolved an issue where form subclasses sharing a base widget instance would experience unexpected mutations in widget forward configurations.

archTortugax and others added 4 commits April 27, 2026 11:46
…oss form subclasses

Closes yourlabs#1333. Port of upstream PR yourlabs#1358.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…e plan

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix: clone forward list to prevent shared mutation across form subclasses (yourlabs#1333)
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 27, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 82faa194-404c-424c-b7a4-e81d192b264b

📥 Commits

Reviewing files that changed from the base of the PR and between 1280e8b and 440ded7.

📒 Files selected for processing (3)
  • CHANGELOG
  • src/dal/widgets.py
  • test_project/tests/test_widgets.py

📝 Walkthrough

Walkthrough

The pull request addresses a bug where form subclasses sharing a base widget instance could silently mutate each other's forward configuration. The WidgetMixin now ensures the forward list is copied during initialization and deep-copying, and test coverage is added to verify the fix.

Changes

Cohort / File(s) Summary
Widget Mixin Fix
src/dal/widgets.py
Modified __init__ to convert forward to a new list instance and added __deepcopy__ method to copy the forward list when cloning, preventing shared state.
Test Coverage
test_project/tests/test_widgets.py
Added new test case verifying that forward configuration is not shared across multiple form subclass instances inheriting from the same base widget.
Release Documentation
CHANGELOG
Added 4.0.1 release section documenting the fix for issue #1333 regarding WidgetMixin.forward mutation when shared across form subclasses.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 Hop hop, the forward lists once did stray,
Shared 'cross the widgets in a tangled way,
Now each gets its copy, distinct and clean,
No silent mutations in between!
Deep-copy hops with glee so bright,
Making widget sharing perfectly right!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main fix: cloning the forward list to prevent shared mutation across form subclasses, matching the core changes in WidgetMixin.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@jpic jpic merged commit 48a48e0 into yourlabs:master Apr 28, 2026
8 checks passed
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.

3 participants