Skip to content

Commit

Permalink
Fix issue with patching staticmethod w/ staticmethod
Browse files Browse the repository at this point in the history
Summary: Fixes a small issue I noticed while working on D52525922.  When we go to handle a value being patched we don't do the unwrapping of the static/class method.  So this moves that logic into `update_thunk` and moves the `_PyClassLoader_ResolveFunction` unwrapping to only happen in the case where we're not returning a thunk.

Reviewed By: carljm

Differential Revision: D52527349

fbshipit-source-id: fbe49c2ced72c68b1467a607ad20a2987c90c36c
  • Loading branch information
DinoV authored and facebook-github-bot committed Jan 13, 2024
1 parent abec6ec commit b1a7249
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 9 deletions.
23 changes: 14 additions & 9 deletions cinderx/StaticPython/classloader.c
Original file line number Diff line number Diff line change
Expand Up @@ -2807,8 +2807,13 @@ update_thunk(_Py_StaticThunk *thunk, PyObject *previous, PyObject *new_value)
{
Py_CLEAR(thunk->thunk_tcs.tcs_value);
if (new_value != NULL) {
thunk->thunk_tcs.tcs_value = new_value;
Py_INCREF(new_value);
PyObject *unwrapped_new = classloader_maybe_unwrap_callable(new_value);
if (unwrapped_new != NULL) {
thunk->thunk_tcs.tcs_value = unwrapped_new;
} else {
thunk->thunk_tcs.tcs_value = new_value;
Py_INCREF(new_value);
}
}
PyObject *funcref;
if (new_value == previous) {
Expand Down Expand Up @@ -4258,6 +4263,13 @@ _PyClassLoader_ResolveFunction(PyObject *path, PyObject **container)
original = NULL;
}

if (original != NULL) {
PyObject *res = (PyObject *)get_or_make_thunk(func, original, *container, containerkey);
Py_DECREF(func);
assert(res != NULL);
return res;
}

if (func != NULL) {
if (Py_TYPE(func) == &PyStaticMethod_Type) {
PyObject *res = Ci_PyStaticMethod_GetFunc(func);
Expand All @@ -4273,13 +4285,6 @@ _PyClassLoader_ResolveFunction(PyObject *path, PyObject **container)
}
}

if (original != NULL) {
PyObject *res = (PyObject *)get_or_make_thunk(func, original, *container, containerkey);
Py_DECREF(func);
assert(res != NULL);
return res;
}

return func;
}

Expand Down
22 changes: 22 additions & 0 deletions cinderx/test_cinderx/test_compiler/test_static/patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,28 @@ def g():
with patch(f"{mod.__name__}.C.f", autospec=True, return_value=100) as p:
self.assertEqual(g(), 100)

def test_patch_staticmethod_with_staticmethod(self):
codestr = """
class C:
@staticmethod
def f():
return 42
def g():
return C.f()
"""
with self.in_module(codestr) as mod:
g = mod.g
for i in range(100):
self.assertEqual(g(), 42)

@staticmethod
def new():
return 100

mod.C.f = new
self.assertEqual(g(), 100)

def test_patch_static_function_non_autospec(self):
codestr = """
class C:
Expand Down

0 comments on commit b1a7249

Please sign in to comment.