Skip to content

Conversation

@medismailben
Copy link
Member

@medismailben medismailben commented Dec 1, 2025

Extract __func__ attribute from staticmethod/classmethod descriptors before treating them as callables. Python's @staticmethod and @classmethod decorators wrap methods in descriptor objects that are not directly usable as PythonCallable, when calling PyCallable_Check.

The actual callable function is stored in the __func__ attribute of these descriptors, so we need to unwrap them to properly validate and invoke the decorated methods in scripted interfaces.

@llvmbot
Copy link
Member

llvmbot commented Dec 1, 2025

@llvm/pr-subscribers-lldb

Author: Med Ismail Bennani (medismailben)

Changes

Extract __func__ attribute from staticmethod/classmethod descriptors before treating them as callables. Python's @staticmethod and @classmethod decorators wrap methods in descriptor objects that are not directly usable as PythonCallable, when calling PyCallable_Check.

The actual callable function is stored in the __func__ attribute of these descriptors, so we need to unwrap them to properly validate and invoke decorated methods in scripted interfaces.


Full diff: https://github.com/llvm/llvm-project/pull/170188.diff

1 Files Affected:

  • (modified) lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h (+11-1)
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
index af88a69e34a13..d9cebefff5ff5 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
@@ -81,7 +81,17 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
                               AbstractMethodCheckerCases::eNotAllocated)
       }
 
-      PythonCallable callable = callable_or_err->AsType<PythonCallable>();
+      PythonObject method_obj = *callable_or_err;
+
+      // Handle staticmethod/classmethod descriptors by extracting __func__
+      if (method_obj.HasAttribute("__func__")) {
+        method_obj = method_obj.GetAttributeValue("__func__");
+        if (!method_obj.IsAllocated())
+          SET_CASE_AND_CONTINUE(method_name,
+                                AbstractMethodCheckerCases::eNotAllocated)
+      }
+
+      PythonCallable callable = method_obj.AsType<PythonCallable>();
       if (!callable)
         SET_CASE_AND_CONTINUE(method_name,
                               AbstractMethodCheckerCases::eNotCallable)

@medismailben medismailben force-pushed the abstract-staticmethod-callable-check branch from 8811cba to b1272a9 Compare December 1, 2025 19:23

// Handle staticmethod/classmethod descriptors by extracting the
// `__func__` attribute.
if (method_obj.HasAttribute("__func__")) {
Copy link
Member

Choose a reason for hiding this comment

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

Do you think we may need this logic elsewhere? If so, would it make sense to put this into a static method in PythonCallable? Something like Expected<PythonCallable> PythonCallable::GetCallable(PythonObject* object)?

Copy link
Member Author

Choose a reason for hiding this comment

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

I moved this as part of static bool PythonCallable::Check which I think makes most sense. T::Check gets invoked when calling T PythonObject::AsType<T>.

…nterface

Extract `__func__` attribute from staticmethod/classmethod descriptors
before treating them as callables. Python's @staticmethod and @classmethod
decorators wrap methods in descriptor objects that are not directly usable
as PythonCallable, when calling PyCallable_Check.

The actual callable function is stored in the `__func__` attribute of these
descriptors, so we need to unwrap them to properly validate and invoke
the decorated methods in scripted interfaces.

Signed-off-by: Med Ismail Bennani <ismail@bennani.ma>
@medismailben medismailben force-pushed the abstract-staticmethod-callable-check branch from b1272a9 to 9fa429e Compare December 1, 2025 20:48
Copy link
Member

@JDevlieghere JDevlieghere left a comment

Choose a reason for hiding this comment

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

Nice

@medismailben medismailben merged commit 3ca85e7 into llvm:main Dec 1, 2025
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants