Skip to content

Commit c8935f8

Browse files
committed
Implement '__kwdefaults__' attribute for function objects.
1 parent 9c7411c commit c8935f8

File tree

3 files changed

+67
-2
lines changed

3 files changed

+67
-2
lines changed

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ def f2(a=f(1, 2), b=10):
7272
return a, b
7373

7474

75+
def f3(a, b=f(1,2), c=10, *args, d="hello", e="world"):
76+
return a, b, c, args, d, e
77+
78+
7579
class MyClass(object):
7680
def __init__(self, x = 10):
7781
pass
@@ -82,6 +86,12 @@ def test_defaults():
8286
assert f2.__defaults__ == ((1, 2, 10, (), {}), 10)
8387

8488

89+
def test_kwdefaults():
90+
assert f.__kwdefaults__ == None
91+
assert f2.__kwdefaults__ == None
92+
assert f3.__kwdefaults__ == { "d": "hello", "e": "world"}
93+
94+
8595
def test_defaults_method():
8696
obj = MyClass()
8797
assert obj.__init__.__defaults__ == (10,)

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/function/FunctionBuiltins.java

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
package com.oracle.graal.python.builtins.objects.function;
2828

2929
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__DEFAULTS__;
30+
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__KWDEFAULTS__;
3031
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__NAME__;
3132
import static com.oracle.graal.python.nodes.SpecialMethodNames.__REDUCE__;
3233
import static com.oracle.graal.python.nodes.SpecialMethodNames.__REPR__;
@@ -41,6 +42,7 @@
4142
import com.oracle.graal.python.builtins.PythonBuiltins;
4243
import com.oracle.graal.python.builtins.objects.PNone;
4344
import com.oracle.graal.python.builtins.objects.function.FunctionBuiltinsFactory.GetFunctionDefaultsNodeFactory;
45+
import com.oracle.graal.python.builtins.objects.function.FunctionBuiltinsFactory.GetFunctionKeywordDefaultsNodeFactory;
4446
import com.oracle.graal.python.builtins.objects.str.PString;
4547
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
4648
import com.oracle.graal.python.nodes.argument.ReadKeywordNode;
@@ -140,7 +142,7 @@ Object setName(Object self, Object value) {
140142
@Builtin(name = __DEFAULTS__, minNumOfPositionalArgs = 1, maxNumOfPositionalArgs = 2, isGetter = true, isSetter = true)
141143
@GenerateNodeFactory
142144
public abstract static class GetFunctionDefaultsNode extends PythonBinaryBuiltinNode {
143-
protected final ConditionProfile nullDefaultsProfile = ConditionProfile.createBinaryProfile();
145+
private final ConditionProfile nullDefaultsProfile = ConditionProfile.createBinaryProfile();
144146

145147
@TruffleBoundary
146148
private static Object[] extractDefaults(PFunction function) {
@@ -181,10 +183,52 @@ public static GetFunctionDefaultsNode create() {
181183
}
182184
}
183185

186+
@Builtin(name = __KWDEFAULTS__, fixedNumOfPositionalArgs = 1, isGetter = true)
187+
@GenerateNodeFactory
188+
public abstract static class GetFunctionKeywordDefaultsNode extends PythonUnaryBuiltinNode {
189+
@TruffleBoundary
190+
private static PKeyword[] extractDefaults(PFunction function) {
191+
ArrayList<PKeyword> kwdefaults = new ArrayList<>();
192+
List<ReadKeywordNode> readKeywordNodes = NodeUtil.findAllNodeInstances(function.getFunctionRootNode(), ReadKeywordNode.class);
193+
for (ReadKeywordNode readKeywordNode : readKeywordNodes) {
194+
if (!readKeywordNode.canBePositional()) {
195+
Object defaultValue = readKeywordNode.getDefaultValue();
196+
if (defaultValue != null) {
197+
kwdefaults.add(new PKeyword(readKeywordNode.getName(), defaultValue));
198+
}
199+
}
200+
}
201+
202+
return kwdefaults.toArray(new PKeyword[0]);
203+
}
204+
205+
@Specialization(guards = "!takesVarargs(self)")
206+
Object doNoKeywordOnlyArgs(@SuppressWarnings("unused") PFunction self) {
207+
return PNone.NONE;
208+
}
209+
210+
@Specialization(guards = "takesVarargs(self)")
211+
Object doGeneric(PFunction self) {
212+
PKeyword[] kwdefaults = extractDefaults(self);
213+
if (kwdefaults.length > 0) {
214+
return factory().createDict(kwdefaults);
215+
}
216+
return PNone.NONE;
217+
}
218+
219+
protected static boolean takesVarargs(PFunction self) {
220+
return self.getArity().takesVarArgs();
221+
}
222+
223+
public static GetFunctionKeywordDefaultsNode create() {
224+
return GetFunctionKeywordDefaultsNodeFactory.create();
225+
}
226+
}
227+
184228
@Builtin(name = __REDUCE__, fixedNumOfPositionalArgs = 1)
185229
@GenerateNodeFactory
186230
public abstract static class ReduceNode extends PythonUnaryBuiltinNode {
187-
@Specialization
231+
@Fallback
188232
Object doGeneric(@SuppressWarnings("unused") Object obj) {
189233
throw raise(TypeError, "can't pickle function objects");
190234
}

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__CODE__;
3030
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__DEFAULTS__;
3131
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__FUNC__;
32+
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__KWDEFAULTS__;
3233
import static com.oracle.graal.python.nodes.SpecialMethodNames.__REDUCE__;
3334
import static com.oracle.graal.python.nodes.SpecialMethodNames.__REPR__;
3435
import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError;
@@ -108,6 +109,16 @@ Object defaults(PMethod self,
108109
}
109110
}
110111

112+
@Builtin(name = __KWDEFAULTS__, fixedNumOfPositionalArgs = 1, isGetter = true)
113+
@GenerateNodeFactory
114+
public abstract static class GetMethodKwdefaultsNode extends PythonUnaryBuiltinNode {
115+
@Specialization
116+
Object defaults(PMethod self,
117+
@Cached("create()") FunctionBuiltins.GetFunctionKeywordDefaultsNode getFunctionKwdefaultsNode) {
118+
return getFunctionKwdefaultsNode.execute(self.getFunction());
119+
}
120+
}
121+
111122
@Builtin(name = __REDUCE__, fixedNumOfPositionalArgs = 1)
112123
@GenerateNodeFactory
113124
public abstract static class ReduceNode extends PythonUnaryBuiltinNode {

0 commit comments

Comments
 (0)