Skip to content

Commit 6b5aedd

Browse files
committed
add support for calling __getattr__ when __getattribute__ raises AttributeError
1 parent 39a2681 commit 6b5aedd

File tree

2 files changed

+62
-5
lines changed

2 files changed

+62
-5
lines changed

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

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,37 @@ def set_dict_attr():
6060
assert_raises(AttributeError, set_dict_attr)
6161

6262
class MyClass(object):
63-
pass
63+
def __init__(self):
64+
self.a = 9
6465

6566
m = MyClass()
66-
assert m.__dict__ == {}
67+
assert m.a == 9
68+
assert m.__dict__ == {'a': 9}
69+
assert m.a == 9
6770
m.__dict__ = {'a': 10}
6871
assert m.__dict__ == {'a': 10}
6972
assert m.a == 10
7073

74+
class MyOtherClass(object):
75+
def __getattribute__(self, item):
76+
return object.__getattribute__(self, item)
77+
78+
def __getattr__(self, item):
79+
if item == "my_attr":
80+
return 10
81+
raise AttributeError
82+
83+
m1 = MyOtherClass()
84+
print()
85+
86+
def get_non_existing_attr():
87+
return m1.my_attr_2
88+
89+
assert_raises(AttributeError, get_non_existing_attr)
90+
assert m1.my_attr == 10
91+
assert "my_attr" not in m1.__dict__
92+
93+
m1.__dict__ = {'d': 10}
94+
assert m1.my_attr == 10
95+
assert "my_attr" not in m1.__dict__
96+
assert m1.d == 10

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

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,29 @@
4141
package com.oracle.graal.python.nodes.attributes;
4242

4343
import static com.oracle.graal.python.nodes.SpecialMethodNames.__GETATTRIBUTE__;
44+
import static com.oracle.graal.python.nodes.SpecialMethodNames.__GETATTR__;
45+
import static com.oracle.graal.python.runtime.exception.PythonErrorType.AttributeError;
4446

4547
import com.oracle.graal.python.nodes.call.special.LookupAndCallBinaryNode;
4648
import com.oracle.graal.python.nodes.expression.ExpressionNode;
4749
import com.oracle.graal.python.nodes.frame.ReadNode;
4850
import com.oracle.graal.python.nodes.statement.StatementNode;
51+
import com.oracle.graal.python.runtime.exception.PException;
52+
import com.oracle.truffle.api.CompilerDirectives;
53+
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
4954
import com.oracle.truffle.api.dsl.NodeChild;
5055
import com.oracle.truffle.api.dsl.Specialization;
5156
import com.oracle.truffle.api.nodes.UnexpectedResultException;
57+
import com.oracle.truffle.api.profiles.ConditionProfile;
5258

5359
@NodeChild(value = "object", type = ExpressionNode.class)
5460
public abstract class GetAttributeNode extends ExpressionNode implements ReadNode {
5561

5662
private final String key;
5763

5864
@Child LookupAndCallBinaryNode dispatchNode = LookupAndCallBinaryNode.create(__GETATTRIBUTE__);
65+
@Child LookupAndCallBinaryNode dispatchGetAttr;
66+
@CompilationFinal private ConditionProfile errorProfile = ConditionProfile.createBinaryProfile();
5967

6068
protected GetAttributeNode(String key) {
6169
this.key = key;
@@ -77,16 +85,39 @@ public static GetAttributeNode create(String key, ExpressionNode object) {
7785

7886
@Specialization(rewriteOn = UnexpectedResultException.class)
7987
protected int doItInt(Object object) throws UnexpectedResultException {
80-
return dispatchNode.executeInt(object, key);
88+
try {
89+
return dispatchNode.executeInt(object, key);
90+
} catch (PException pe) {
91+
pe.expect(AttributeError, getCore(), errorProfile);
92+
return getDispatchGetAttr().executeInt(object, key);
93+
}
8194
}
8295

8396
@Specialization(rewriteOn = UnexpectedResultException.class)
8497
protected boolean doItBoolean(Object object) throws UnexpectedResultException {
85-
return dispatchNode.executeBool(object, key);
98+
try {
99+
return dispatchNode.executeBool(object, key);
100+
} catch (PException pe) {
101+
pe.expect(AttributeError, getCore(), errorProfile);
102+
return getDispatchGetAttr().executeBool(object, key);
103+
}
86104
}
87105

88106
@Specialization(replaces = {"doItInt", "doItBoolean"})
89107
protected Object doIt(Object object) {
90-
return dispatchNode.executeObject(object, key);
108+
try {
109+
return dispatchNode.executeObject(object, key);
110+
} catch (PException pe) {
111+
pe.expect(AttributeError, getCore(), errorProfile);
112+
return getDispatchGetAttr().executeObject(object, key);
113+
}
114+
}
115+
116+
private LookupAndCallBinaryNode getDispatchGetAttr() {
117+
if (dispatchGetAttr == null) {
118+
CompilerDirectives.transferToInterpreterAndInvalidate();
119+
dispatchGetAttr = insert(LookupAndCallBinaryNode.create(__GETATTR__));
120+
}
121+
return dispatchGetAttr;
91122
}
92123
}

0 commit comments

Comments
 (0)