Skip to content

Conversation

@masenf
Copy link
Collaborator

@masenf masenf commented Nov 14, 2025

When calling a method on an arbitrary wrapped object, rebind it's self as the mutable proxy so changes made inside the method are also tracked.

(Previously only wrapped Base instances had in-method tracking).

When calling a method on an arbitrary wrapped object, rebind it's `self` as the
mutable proxy so changes made inside the method are also tracked.

(Previously only wrapped `Base` instances had in-method tracking).
@codspeed-hq
Copy link

codspeed-hq bot commented Nov 14, 2025

CodSpeed Performance Report

Merging #5979 will not alter performance

Comparing masenf/dataclass-mutable-proxy (507e804) with main (a679316)

Summary

✅ 8 untouched

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Nov 14, 2025

Greptile Overview

Greptile Summary

This PR extends method wrapping in MutableProxy to support dataclasses and pydantic BaseModel instances, not just Reflex Base subclasses. The key change is in the conditional logic: previously, only methods on Base instances were wrapped to track internal mutations; now, methods on ANY object type are wrapped (except for Base methods explicitly listed in NEVER_WRAP_BASE_ATTRS).

Key changes:

  • Modified the wrapping condition from isinstance(Base) AND not_in_never_wrap to (NOT isinstance(Base) OR not_in_never_wrap) - this ensures dataclasses and pydantic models also get their methods wrapped
  • Methods are rebound with the MutableProxy as self using functools.partial, so mutations inside the method are properly tracked
  • Added comprehensive tests verifying that mutating methods (like set_foo) mark state dirty, while read-only methods (like double_foo) and copy methods don't

The logic transformation is correct and the test coverage is thorough.

Confidence Score: 5/5

  • This PR is safe to merge with no identified issues
  • The boolean logic transformation is mathematically correct and properly extends method wrapping to non-Base objects. The change is well-tested with comprehensive coverage of both mutation-tracking and non-mutation cases across dataclasses, pydantic v1, and pydantic v2 models. The implementation correctly preserves existing behavior for Base instances while adding the desired functionality for other object types.
  • No files require special attention

Important Files Changed

File Analysis

Filename Score Overview
reflex/istate/proxy.py 5/5 Extended method wrapping from Base subclasses to all objects (dataclasses, pydantic models), enabling proper change tracking for method calls on any mutable state object
tests/units/test_state.py 5/5 Added comprehensive test coverage for method wrapping on dataclasses and pydantic BaseModel instances, verifying both mutating methods (set_foo) and read-only methods (double_foo)

Sequence Diagram

sequenceDiagram
    participant User as Event Handler
    participant MP as MutableProxy
    participant Obj as Wrapped Object (dataclass/BaseModel)
    participant State as State Manager
    
    User->>MP: Call method (e.g., obj.set_foo("val"))
    MP->>MP: __getattr__("set_foo")
    
    alt Method is callable with __func__
        alt Not Base OR not in NEVER_WRAP_BASE_ATTRS
            MP->>MP: Wrap with functools.partial(method.__func__, self)
            MP->>MP: Apply _wrap_recursive_decorator
            Note over MP: Rebind method's self to MutableProxy<br/>so changes are tracked
        end
    end
    
    MP->>Obj: Execute method with proxy as self
    Obj->>MP: self.foo = "val" (via proxy)
    MP->>MP: __setattr__ triggered
    MP->>State: Mark var as dirty
    MP-->>User: Return method result
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

@masenf masenf merged commit 1d4bfe0 into main Nov 14, 2025
50 of 53 checks passed
@masenf masenf deleted the masenf/dataclass-mutable-proxy branch November 14, 2025 22:10
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