Skip to content

Conversation

@masenf
Copy link
Collaborator

@masenf masenf commented Nov 19, 2025

For arbitrary methods, we assume the return value is not associated directly with the dirty state of the class. If the method does mutate some value on the self, then it will still be marked dirty by virtue of self being bound to the MutableProxy.

For arbitrary methods, we assume the return value is not associated directly
with the dirty state of the class. If the method _does_ mutate some value on
the `self`, then it will still be marked dirty by virtue of `self` being bound
to the MutableProxy.
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Nov 19, 2025

Greptile Summary

  • Changed MutableProxy.__getattr__ to stop wrapping method return values, fixing issue where copying dataclass/model instances incorrectly marked state as dirty
  • Added comprehensive tests verifying that copies of mutable objects can be modified without affecting the original state's dirty tracking

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The change is well-targeted and fixes a legitimate bug where method return values were incorrectly wrapped in MutableProxy. The fix correctly distinguishes between methods that mutate self (still tracked via proxy binding) and methods that return new instances (no longer wrapped). Comprehensive tests verify both the fix and that existing behavior is preserved.
  • No files require special attention

Important Files Changed

Filename Overview
reflex/istate/proxy.py Removed wrapping of method return values to prevent false dirty state marking when methods return new instances

Sequence Diagram

sequenceDiagram
    participant User
    participant State
    participant MutableProxy
    participant Method
    participant DataClass
    
    User->>State: Access `state.dc.copy()`
    State->>MutableProxy: `__getattr__("copy")`
    MutableProxy->>MutableProxy: Detect method with `__func__`
    MutableProxy->>Method: Rebind self using `functools.partial`
    Method->>DataClass: Call `dataclasses.replace(self, **kwargs)`
    DataClass-->>Method: Return new DataClass instance (unwrapped)
    Method-->>User: Return new instance
    User->>DataClass: Modify copy with `dc_copy.foo = "new"`
    Note over State: State remains clean (no dirty vars marked)
Loading

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

2 files reviewed, no comments

Edit Code Review Agent Settings | Greptile
React with 👍 or 👎 to share your feedback on this new summary format

@codspeed-hq
Copy link

codspeed-hq bot commented Nov 19, 2025

CodSpeed Performance Report

Merging #5986 will not alter performance

Comparing masenf/mutable-proxy-methods2 (5a47690) with main (4ee713f)

Summary

✅ 8 untouched

@masenf masenf merged commit a987437 into main Nov 19, 2025
46 of 47 checks passed
@masenf masenf deleted the masenf/mutable-proxy-methods2 branch November 19, 2025 01:26
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