Skip MutableProxy rebind self for _sa_instrumented functions#6168
Skip MutableProxy rebind self for _sa_instrumented functions#6168
Conversation
Not a general solution to the issue of cases where rebinding `self` might break descriptors, but at least fix the case for sqlalchemy models. Fix #6167
Greptile SummaryThis PR adds a targeted one-line guard in
Confidence Score: 4/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[MutableProxy.__getattr__ name] --> B[value = super.__getattr__ name]
B --> C{callable value}
C -- No --> G[wrap in MutableProxy if mutable]
C -- Yes --> D{has __func__ AND self is not a class}
D -- No --> G
D -- Yes --> E{value._sa_instrumented is True - NEW CHECK}
E -- Yes --> F[Return value as-is - SQLAlchemy descriptor preserved]
E -- No --> H[Return functools.partial func self - self rebound to proxy]
G --> I[Return value]
F --> I
H --> I
Last reviewed commit: faba1e4 |
| and (func := getattr(value, "__func__", None)) is not None | ||
| and not inspect.isclass(getattr(value, "__self__", None)) | ||
| # skip SQLAlchemy instrumented methods | ||
| and not getattr(value, "_sa_instrumented", False) |
There was a problem hiding this comment.
No regression test for the SQLAlchemy fix
The fix addresses a real bug (issue #6167) but no test was added to tests/units/istate/test_proxy.py (or elsewhere) to assert the behavior. Without a test, a future refactor of the rebinding logic could silently reintroduce the breakage.
Consider adding a minimal test that:
- Creates a mock object with a method that has
_sa_instrumented = Trueset on it. - Wraps it in
MutableProxy. - Asserts that accessing the method via the proxy does not rebind
self(i.e. calling the method works as expected on the underlying object, not the proxy).
def test_mutable_proxy_skips_sa_instrumented():
class FakeModel:
def instrumented_method(self):
return type(self).__name__
instrumented_method = FakeModel.instrumented_method
instrumented_method._sa_instrumented = True
FakeModel.instrumented_method = instrumented_method
proxy = MutableProxy(FakeModel(), state=None, field_name="")
# Should return "FakeModel", not "MutableProxy"
assert proxy.instrumented_method() == "FakeModel"
Not a general solution to the issue of cases where rebinding
selfmight break descriptors, but at least fix the case for sqlalchemy models.Fix #6167