Skip to content

Commit 1759c41

Browse files
committed
[GR-62204] Fix to use overridden __qualname__ when that is set on a method's function.
PullRequest: graalpython/4345
2 parents 08e5df6 + 1b32f7c commit 1759c41

File tree

2 files changed

+46
-93
lines changed

2 files changed

+46
-93
lines changed

graalpython/com.oracle.graal.python.test/src/tests/test_methods.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
1+
# Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
22
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
33
#
44
# The Universal Permissive License (UPL), Version 1.0
@@ -89,3 +89,21 @@ def __call__(self, x, y):
8989

9090
assert isinstance(method1(), A)
9191
assert method2(1) == "A is 1", method2(1)
92+
93+
94+
def test_method_qualname_uses_wrapped_callable():
95+
import types
96+
97+
def f():
98+
pass
99+
100+
class A:
101+
def g(self):
102+
pass
103+
104+
m = classmethod(f)
105+
106+
assert A().g.__qualname__ == "test_method_qualname_uses_wrapped_callable.<locals>.A.g"
107+
assert types.MethodType(f, A).__qualname__ == "test_method_qualname_uses_wrapped_callable.<locals>.f"
108+
assert A.m.__qualname__ == "test_method_qualname_uses_wrapped_callable.<locals>.f"
109+
assert A.__dict__["m"].__qualname__ == "test_method_qualname_uses_wrapped_callable.<locals>.f"

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/method/AbstractMethodBuiltins.java

Lines changed: 27 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, 2025, Oracle and/or its affiliates.
2+
* Copyright (c) 2017, 2026, Oracle and/or its affiliates.
33
* Copyright (c) 2014, Regents of the University of California
44
*
55
* All rights reserved.
@@ -55,10 +55,8 @@
5555
import com.oracle.graal.python.builtins.objects.cext.PythonAbstractNativeObject;
5656
import com.oracle.graal.python.builtins.objects.function.PKeyword;
5757
import com.oracle.graal.python.builtins.objects.module.PythonModule;
58-
import com.oracle.graal.python.builtins.objects.str.StringUtils.SimpleTruffleStringFormatNode;
5958
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
6059
import com.oracle.graal.python.builtins.objects.type.TpSlots;
61-
import com.oracle.graal.python.builtins.objects.type.TypeNodes;
6260
import com.oracle.graal.python.builtins.objects.type.slots.TpSlotHashFun.HashBuiltinNode;
6361
import com.oracle.graal.python.builtins.objects.type.slots.TpSlotRichCompare.RichCmpBuiltinNode;
6462
import com.oracle.graal.python.lib.PyObjectGetAttr;
@@ -76,15 +74,13 @@
7674
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
7775
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
7876
import com.oracle.graal.python.nodes.function.builtins.PythonVarargsBuiltinNode;
79-
import com.oracle.graal.python.nodes.object.GetClassNode;
8077
import com.oracle.graal.python.nodes.util.CannotCastException;
8178
import com.oracle.graal.python.nodes.util.CastToTruffleStringNode;
8279
import com.oracle.graal.python.runtime.ExecutionContext.BoundaryCallContext;
8380
import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData;
8481
import com.oracle.graal.python.runtime.PythonContext;
8582
import com.oracle.graal.python.runtime.object.PFactory;
8683
import com.oracle.graal.python.util.PythonUtils;
87-
import com.oracle.truffle.api.CompilerDirectives;
8884
import com.oracle.truffle.api.dsl.Bind;
8985
import com.oracle.truffle.api.dsl.Cached;
9086
import com.oracle.truffle.api.dsl.Cached.Shared;
@@ -285,105 +281,44 @@ static Object getDoc(PBuiltinMethod self,
285281
}
286282
}
287283

284+
static TruffleString getFunctionAttr(VirtualFrame frame, Object self, Node inliningTarget, CastToTruffleStringNode toStringNode, PyObjectGetAttr getAttr, PRaiseNode raiseNode,
285+
TruffleString attrName) {
286+
Object function;
287+
if (self instanceof PMethod method) {
288+
function = method.getFunction();
289+
} else {
290+
function = ((PBuiltinMethod) self).getFunction();
291+
}
292+
try {
293+
return toStringNode.execute(inliningTarget, getAttr.execute(frame, inliningTarget, function, attrName));
294+
} catch (CannotCastException cce) {
295+
throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.TypeError, ErrorMessages.IS_NOT_A_UNICODE_OBJECT, attrName);
296+
}
297+
}
298+
288299
@Builtin(name = J___NAME__, minNumOfPositionalArgs = 1, isGetter = true)
289300
@GenerateNodeFactory
290301
public abstract static class NameNode extends PythonUnaryBuiltinNode {
291302
@Specialization
292-
static Object getName(VirtualFrame frame, PBuiltinMethod method,
293-
@Bind Node inliningTarget,
294-
@Shared("toStringNode") @Cached CastToTruffleStringNode toStringNode,
295-
@Shared("getAttr") @Cached PyObjectGetAttr getAttr) {
296-
try {
297-
return toStringNode.execute(inliningTarget, getAttr.execute(frame, inliningTarget, method.getFunction(), T___NAME__));
298-
} catch (CannotCastException cce) {
299-
throw CompilerDirectives.shouldNotReachHere();
300-
}
301-
}
302-
303-
@Specialization
304-
static Object getName(VirtualFrame frame, PMethod method,
303+
static TruffleString getName(VirtualFrame frame, Object self,
305304
@Bind Node inliningTarget,
306-
@Shared("toStringNode") @Cached CastToTruffleStringNode toStringNode,
307-
@Shared("getAttr") @Cached PyObjectGetAttr getAttr) {
308-
try {
309-
return toStringNode.execute(inliningTarget, getAttr.execute(frame, inliningTarget, method.getFunction(), T___NAME__));
310-
} catch (CannotCastException cce) {
311-
throw CompilerDirectives.shouldNotReachHere();
312-
}
305+
@Cached CastToTruffleStringNode toStringNode,
306+
@Cached PyObjectGetAttr getAttr,
307+
@Cached PRaiseNode raiseNode) {
308+
return getFunctionAttr(frame, self, inliningTarget, toStringNode, getAttr, raiseNode, T___NAME__);
313309
}
314310
}
315311

316312
@Builtin(name = J___QUALNAME__, minNumOfPositionalArgs = 1, isGetter = true)
317313
@GenerateNodeFactory
318314
public abstract static class QualNameNode extends PythonUnaryBuiltinNode {
319-
320-
protected static boolean isSelfModuleOrNull(PMethod method) {
321-
return method.getSelf() == PNone.NO_VALUE || PGuards.isPythonModule(method.getSelf());
322-
}
323-
324-
protected static boolean isSelfModuleOrNull(PBuiltinMethod method) {
325-
return method.getSelf() == PNone.NO_VALUE || PGuards.isPythonModule(method.getSelf());
326-
}
327-
328-
@Specialization(guards = "isSelfModuleOrNull(method)")
329-
static TruffleString doSelfIsModule(VirtualFrame frame, PMethod method,
330-
@Bind Node inliningTarget,
331-
@Shared("toStringNode") @Cached CastToTruffleStringNode toStringNode,
332-
@Shared("lookupName") @Cached PyObjectLookupAttr lookupName) {
333-
return getName(frame, inliningTarget, method.getFunction(), toStringNode, lookupName);
334-
}
335-
336-
@Specialization(guards = "isSelfModuleOrNull(method)")
337-
static TruffleString doSelfIsModule(VirtualFrame frame, PBuiltinMethod method,
338-
@Bind Node inliningTarget,
339-
@Shared("toStringNode") @Cached CastToTruffleStringNode toStringNode,
340-
@Shared("lookupName") @Cached PyObjectLookupAttr lookupName) {
341-
return getName(frame, inliningTarget, method.getFunction(), toStringNode, lookupName);
342-
}
343-
344-
@Specialization(guards = "!isSelfModuleOrNull(method)")
345-
static TruffleString doSelfIsObject(VirtualFrame frame, PMethod method,
346-
@Bind Node inliningTarget,
347-
@Shared @Cached GetClassNode getClassNode,
348-
@Shared @Cached TypeNodes.IsTypeNode isTypeNode,
349-
@Shared("toStringNode") @Cached CastToTruffleStringNode toStringNode,
350-
@Shared("getQualname") @Cached PyObjectGetAttr getQualname,
351-
@Shared("lookupName") @Cached PyObjectLookupAttr lookupName,
352-
@Shared("formatter") @Cached SimpleTruffleStringFormatNode simpleTruffleStringFormatNode,
353-
@Shared @Cached PRaiseNode raiseNode) {
354-
return getQualName(frame, inliningTarget, method.getSelf(), method.getFunction(), getClassNode, isTypeNode, toStringNode, getQualname, lookupName, simpleTruffleStringFormatNode,
355-
raiseNode);
356-
}
357-
358-
@Specialization(guards = "!isSelfModuleOrNull(method)")
359-
static TruffleString doSelfIsObject(VirtualFrame frame, PBuiltinMethod method,
315+
@Specialization
316+
static TruffleString getQualname(VirtualFrame frame, Object self,
360317
@Bind Node inliningTarget,
361-
@Shared @Cached GetClassNode getClassNode,
362-
@Shared @Cached TypeNodes.IsTypeNode isTypeNode,
363-
@Shared("toStringNode") @Cached CastToTruffleStringNode toStringNode,
364-
@Shared("getQualname") @Cached PyObjectGetAttr getQualname,
365-
@Shared("lookupName") @Cached PyObjectLookupAttr lookupName,
366-
@Shared("formatter") @Cached SimpleTruffleStringFormatNode simpleTruffleStringFormatNode,
367-
@Shared @Cached PRaiseNode raiseNode) {
368-
return getQualName(frame, inliningTarget, method.getSelf(), method.getFunction(), getClassNode, isTypeNode, toStringNode, getQualname, lookupName, simpleTruffleStringFormatNode,
369-
raiseNode);
370-
}
371-
372-
private static TruffleString getQualName(VirtualFrame frame, Node inliningTarget, Object self, Object func, GetClassNode getClassNode, TypeNodes.IsTypeNode isTypeNode,
373-
CastToTruffleStringNode toStringNode, PyObjectGetAttr getQualname, PyObjectLookupAttr lookupName, SimpleTruffleStringFormatNode simpleTruffleStringFormatNode,
374-
PRaiseNode raiseNode) {
375-
Object type = isTypeNode.execute(inliningTarget, self) ? self : getClassNode.execute(inliningTarget, self);
376-
377-
try {
378-
TruffleString typeQualName = toStringNode.execute(inliningTarget, getQualname.execute(frame, inliningTarget, type, T___QUALNAME__));
379-
return simpleTruffleStringFormatNode.format("%s.%s", typeQualName, getName(frame, inliningTarget, func, toStringNode, lookupName));
380-
} catch (CannotCastException cce) {
381-
throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.TypeError, ErrorMessages.IS_NOT_A_UNICODE_OBJECT, T___QUALNAME__);
382-
}
383-
}
384-
385-
private static TruffleString getName(VirtualFrame frame, Node inliningTarget, Object func, CastToTruffleStringNode toStringNode, PyObjectLookupAttr lookupName) {
386-
return toStringNode.execute(inliningTarget, lookupName.execute(frame, inliningTarget, func, T___NAME__));
318+
@Cached CastToTruffleStringNode toStringNode,
319+
@Cached PyObjectGetAttr getQualname,
320+
@Cached PRaiseNode raiseNode) {
321+
return getFunctionAttr(frame, self, inliningTarget, toStringNode, getQualname, raiseNode, T___QUALNAME__);
387322
}
388323
}
389324

0 commit comments

Comments
 (0)