Skip to content

Commit 3e10902

Browse files
committed
Fix AttributeError message for types
1 parent 5754a47 commit 3e10902

3 files changed

Lines changed: 32 additions & 4 deletions

File tree

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

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
1+
# Copyright (c) 2024, 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
@@ -77,3 +77,30 @@ def __eq__(self, other):
7777
o = ObjWithHashSlot()
7878
o.__hash__ = lambda: 1
7979
assert hash(o) == 1
80+
81+
82+
def test_attribute_error_message():
83+
obj = object()
84+
85+
try:
86+
obj.foo
87+
except AttributeError as e:
88+
assert e.obj == obj
89+
assert e.name == "foo"
90+
assert str(e) == "'object' object has no attribute 'foo'"
91+
92+
try:
93+
obj.foo = 1
94+
except AttributeError as e:
95+
# Note: as of 3.12, CPython doesn't set obj and name
96+
assert str(e) == "'object' object has no attribute 'foo'"
97+
98+
class MyClass:
99+
pass
100+
101+
try:
102+
MyClass.foo
103+
except AttributeError as e:
104+
assert e.obj == MyClass
105+
assert e.name == "foo"
106+
assert str(e) == "type object 'MyClass' has no attribute 'foo'"

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/ErrorMessages.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ public abstract class ErrorMessages {
355355
public static final TruffleString GOT_UNEXPECTED_KEYWORD_ARG = tsLiteral("%s() got an unexpected keyword argument '%s'");
356356
public static final TruffleString HANDLER_MUST_BE_CALLABLE = tsLiteral("handler must be callable");
357357
public static final TruffleString HAS_NO_ATTR = tsLiteral("%p has no attribute '%s'");
358-
public static final TruffleString TYPE_N_HAS_NO_ATTR = tsLiteral("type object %s has no attribute '%s'");
358+
public static final TruffleString TYPE_N_HAS_NO_ATTR = tsLiteral("type object '%N' has no attribute '%s'");
359359
public static final TruffleString P_HAS_NO_ATTRS_S_TO_ASSIGN = tsLiteral("'%p' object has no attributes (assign to .%s)");
360360
public static final TruffleString P_HAS_NO_ATTRS_S_TO_DELETE = tsLiteral("'%p' object has no attributes (del .%s)");
361361
public static final TruffleString P_HAS_RO_ATTRS_S_TO_ASSIGN = tsLiteral("'%p' object has only read-only attributes (assign to .%s)");

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/MergedObjectTypeModuleGetAttributeNode.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -181,7 +181,8 @@ static Object doIt(VirtualFrame frame, Node inliningTarget, Object object, Truff
181181
}
182182
}
183183

184-
throw raiseNode.raiseAttributeError(inliningTarget, ErrorMessages.OBJ_P_HAS_NO_ATTR_S, object, key);
184+
TruffleString errorMessage = cachedSlot != TypeBuiltins.SLOTS.tp_getattro() ? ErrorMessages.OBJ_P_HAS_NO_ATTR_S : ErrorMessages.TYPE_N_HAS_NO_ATTR;
185+
throw raiseNode.raiseAttributeError(inliningTarget, errorMessage, object, key);
185186
} catch (PException e) {
186187
// Extra behavior for module.__getattribute__
187188
if (cachedSlot == ModuleBuiltins.SLOTS.tp_getattro()) {

0 commit comments

Comments
 (0)