Skip to content

Commit e123ddb

Browse files
committed
[GR-10786] test_dict various fixes
PullRequest: graalpython/119
2 parents 238cd0c + 2ba8a9a commit e123ddb

File tree

8 files changed

+202
-26
lines changed

8 files changed

+202
-26
lines changed

graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/builtin/BaseExceptionTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public void testUnhashableType() {
5656
}
5757

5858
@Test
59-
public void testUnsupportedKey() {
59+
public void testClassAsKey() {
6060
String source = "try:\n" +
6161
" class MyClass:\n" +
6262
" def __hash__(self):\n" +
@@ -66,7 +66,7 @@ public void testUnsupportedKey() {
6666
" sysdict[MyClass()] = lambda x: x\n" +
6767
"except KeyError as e:\n" +
6868
" print(str(e))\n";
69-
assertPrints("unsupported key: MyClass\n", source);
69+
assertPrints("", source);
7070
}
7171

7272
@Test

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,3 +425,21 @@ def helper_keys_contained(fn):
425425
# With the same size, an elementwise compare happens
426426
assert larger != larger3
427427
assert not larger == larger3
428+
429+
430+
def test_object_set_item_single_instance_non_str_key():
431+
class Foo(object):
432+
pass
433+
434+
f = Foo()
435+
f.__dict__[1] = 1
436+
f.a = 'a'
437+
assert f.__dict__ == {1: 1, 'a': 'a'}
438+
439+
def bar():
440+
pass
441+
442+
bar.__dict__[1] = 1
443+
bar.a = 'a'
444+
assert 1 in bar.__dict__
445+
assert 'a' in bar.__dict__

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/GcModuleBuiltins.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,12 @@
3333
import com.oracle.graal.python.builtins.CoreFunctions;
3434
import com.oracle.graal.python.builtins.PythonBuiltins;
3535
import com.oracle.graal.python.builtins.objects.PNone;
36+
import com.oracle.graal.python.builtins.objects.cext.PythonNativeClass;
37+
import com.oracle.graal.python.builtins.objects.cext.PythonNativeObject;
3638
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
3739
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
3840
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
41+
import com.oracle.truffle.api.dsl.Fallback;
3942
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
4043
import com.oracle.truffle.api.dsl.Specialization;
4144

@@ -75,4 +78,24 @@ public PTuple count() {
7578
return factory().createTuple(new Object[]{count, 0, 0});
7679
}
7780
}
81+
82+
@Builtin(name = "is_tracked", fixedNumOfArguments = 1)
83+
@GenerateNodeFactory
84+
abstract static class GcIsTrackedNode extends PythonBuiltinNode {
85+
@Specialization
86+
public boolean isTracked(@SuppressWarnings("unused") PythonNativeObject object) {
87+
return false;
88+
}
89+
90+
@Specialization
91+
public boolean isTracked(@SuppressWarnings("unused") PythonNativeClass object) {
92+
// TODO: this is not correct
93+
return true;
94+
}
95+
96+
@Fallback
97+
public boolean isTracked(@SuppressWarnings("unused") Object object) {
98+
return true;
99+
}
100+
}
78101
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/DynamicObjectStorage.java

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,4 +171,118 @@ public HashingStorage copy(Equivalence eq) {
171171
}
172172
}
173173

174+
public static class PythonObjectHybridDictStorage extends DynamicObjectStorage {
175+
private final EconomicMapStorage nonAttributesStorage;
176+
177+
public PythonObjectHybridDictStorage(PythonObjectDictStorage storage) {
178+
this(storage.getStore());
179+
}
180+
181+
public PythonObjectHybridDictStorage(DynamicObject store) {
182+
this(store, EconomicMapStorage.create(false));
183+
}
184+
185+
PythonObjectHybridDictStorage(DynamicObject store, EconomicMapStorage nonAttributesStorage) {
186+
super(store);
187+
this.nonAttributesStorage = nonAttributesStorage;
188+
}
189+
190+
@Override
191+
public int length() {
192+
return super.length() + nonAttributesStorage.length();
193+
}
194+
195+
@Override
196+
public boolean hasKey(Object key, Equivalence eq) {
197+
if (super.hasKey(key, DEFAULT_EQIVALENCE)) {
198+
return true;
199+
}
200+
return nonAttributesStorage.hasKey(key, eq);
201+
}
202+
203+
@Override
204+
public Object getItem(Object key, Equivalence eq) {
205+
Object value = super.getItem(key, DEFAULT_EQIVALENCE);
206+
if (value != null) {
207+
return value;
208+
}
209+
return this.nonAttributesStorage.getItem(key, eq);
210+
}
211+
212+
@Override
213+
public void setItem(Object key, Object value, Equivalence eq) {
214+
if (key instanceof String) {
215+
super.setItem(key, value, DEFAULT_EQIVALENCE);
216+
} else {
217+
this.nonAttributesStorage.setItem(key, value, eq);
218+
}
219+
}
220+
221+
@Override
222+
public boolean remove(Object key, Equivalence eq) {
223+
if (super.remove(key, DEFAULT_EQIVALENCE)) {
224+
return true;
225+
}
226+
return this.nonAttributesStorage.remove(key, eq);
227+
}
228+
229+
@Override
230+
public Iterable<Object> keys() {
231+
if (this.nonAttributesStorage.length() == 0) {
232+
return super.keys();
233+
} else {
234+
ArrayList<Object> entries = new ArrayList<>(this.length());
235+
for (Object entry : super.keys()) {
236+
entries.add(entry);
237+
}
238+
for (Object entry : this.nonAttributesStorage.keys()) {
239+
entries.add(entry);
240+
}
241+
return wrapJavaIterable(entries);
242+
}
243+
}
244+
245+
@Override
246+
public Iterable<Object> values() {
247+
if (this.nonAttributesStorage.length() == 0) {
248+
return super.values();
249+
} else {
250+
ArrayList<Object> entries = new ArrayList<>(this.length());
251+
for (Object entry : super.values()) {
252+
entries.add(entry);
253+
}
254+
for (Object entry : this.nonAttributesStorage.values()) {
255+
entries.add(entry);
256+
}
257+
return wrapJavaIterable(entries);
258+
}
259+
}
260+
261+
@Override
262+
public Iterable<DictEntry> entries() {
263+
if (this.nonAttributesStorage.length() == 0) {
264+
return super.entries();
265+
} else {
266+
ArrayList<DictEntry> entries = new ArrayList<>(this.length());
267+
for (DictEntry entry : super.entries()) {
268+
entries.add(entry);
269+
}
270+
for (DictEntry entry : this.nonAttributesStorage.entries()) {
271+
entries.add(entry);
272+
}
273+
return wrapJavaIterable(entries);
274+
}
275+
}
276+
277+
@Override
278+
public void clear() {
279+
super.clear();
280+
this.nonAttributesStorage.clear();
281+
}
282+
283+
@Override
284+
public HashingStorage copy(Equivalence eq) {
285+
return new PythonObjectHybridDictStorage(getStore().copy(getStore().getShape()), (EconomicMapStorage) nonAttributesStorage.copy(eq));
286+
}
287+
}
174288
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/HashingStorageNodes.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242

4343
import static com.oracle.graal.python.builtins.objects.common.HashingStorage.DEFAULT_EQIVALENCE;
4444
import static com.oracle.graal.python.nodes.SpecialMethodNames.__HASH__;
45-
import static com.oracle.graal.python.runtime.exception.PythonErrorType.KeyError;
4645
import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError;
4746
import static com.oracle.graal.python.runtime.exception.PythonErrorType.ValueError;
4847

@@ -52,6 +51,7 @@
5251
import com.oracle.graal.python.builtins.objects.PNone;
5352
import com.oracle.graal.python.builtins.objects.common.DynamicObjectStorage.FastDictStorage;
5453
import com.oracle.graal.python.builtins.objects.common.DynamicObjectStorage.PythonObjectDictStorage;
54+
import com.oracle.graal.python.builtins.objects.common.DynamicObjectStorage.PythonObjectHybridDictStorage;
5555
import com.oracle.graal.python.builtins.objects.common.HashingStorage.Equivalence;
5656
import com.oracle.graal.python.builtins.objects.common.HashingStorageNodesFactory.ContainsKeyNodeGen;
5757
import com.oracle.graal.python.builtins.objects.common.HashingStorageNodesFactory.ContainsValueNodeGen;
@@ -237,6 +237,12 @@ protected static DynamicObjectStorage switchToFastDictStorage(PHashingCollection
237237
return newStorage;
238238
}
239239

240+
protected static PythonObjectHybridDictStorage switchToHybridDictStorage(PHashingCollection container, PythonObjectDictStorage dictStorage) {
241+
PythonObjectHybridDictStorage newStorage = new PythonObjectHybridDictStorage(dictStorage);
242+
container.setDictStorage(newStorage);
243+
return newStorage;
244+
}
245+
240246
protected static Location lookupLocation(Shape shape, Object name) {
241247
/* Initialization of cached values always happens in a slow path. */
242248
CompilerAsserts.neverPartOfCompilation();
@@ -483,6 +489,11 @@ protected boolean updateShape(DynamicObjectStorage storage, String name) {
483489
return readUncached(storage, name);
484490
}
485491

492+
@Specialization(guards = "!isJavaString(name)")
493+
protected boolean readUncached(PythonObjectHybridDictStorage storage, Object name) {
494+
return storage.hasKey(name, getEquivalence());
495+
}
496+
486497
@Specialization(guards = "!isJavaString(name)")
487498
@SuppressWarnings("unused")
488499
protected boolean readUncached(DynamicObjectStorage storage, Object name) {
@@ -826,9 +837,8 @@ protected void doKeywordsPStringGeneralize(PHashingCollection container, Keyword
826837
}
827838

828839
@Specialization(guards = {"!isJavaString(key)", "isHashable(key)"})
829-
@SuppressWarnings("unused")
830840
protected void doDynamicObjectGeneralize(PHashingCollection container, PythonObjectDictStorage storage, Object key, Object value) {
831-
throw raise(KeyError, "unsupported key: %p", key);
841+
switchToHybridDictStorage(container, storage).setItem(key, value, getEquivalence());
832842
}
833843

834844
@Specialization(guards = {"!isJavaString(key)", "isHashable(key)"})
@@ -965,6 +975,11 @@ protected Object doDynamicObjectUpdateShapePString(DynamicObjectStorage storage,
965975
return doDynamicObjectUncachedPString(storage, name);
966976
}
967977

978+
@Specialization(guards = {"!isJavaString(key)", "isHashable(key)"})
979+
Object doDynamicObject(PythonObjectHybridDictStorage storage, Object key) {
980+
return storage.getItem(key, getEquivalence());
981+
}
982+
968983
@Specialization(guards = {"!isJavaString(key)", "isHashable(key)"})
969984
@SuppressWarnings("unused")
970985
Object doDynamicObject(DynamicObjectStorage storage, Object key) {

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import com.oracle.graal.python.builtins.objects.PNone;
4747
import com.oracle.graal.python.builtins.objects.cell.PCell;
4848
import com.oracle.graal.python.builtins.objects.code.PCode;
49+
import com.oracle.graal.python.builtins.objects.dict.PDict;
4950
import com.oracle.graal.python.builtins.objects.module.PythonModule;
5051
import com.oracle.graal.python.builtins.objects.object.PythonObject;
5152
import com.oracle.graal.python.nodes.argument.CreateArgumentsNode;
@@ -234,7 +235,12 @@ Object builtinCode(PBuiltinFunction self, Object none) {
234235
static abstract class DictNode extends PythonUnaryBuiltinNode {
235236
@Specialization
236237
Object dict(PFunction self) {
237-
return factory().createMappingproxy(self);
238+
PDict dict = self.getDict();
239+
if (dict == null) {
240+
dict = factory().createDictFixedStorage(self);
241+
self.setDict(dict);
242+
}
243+
return dict;
238244
}
239245

240246
@SuppressWarnings("unused")

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/GeneratorBuiltins.java

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727

2828
import static com.oracle.graal.python.nodes.SpecialMethodNames.__ITER__;
2929
import static com.oracle.graal.python.nodes.SpecialMethodNames.__NEXT__;
30-
import static com.oracle.graal.python.runtime.exception.PythonErrorType.NotImplementedError;
3130
import static com.oracle.graal.python.runtime.exception.PythonErrorType.StopIteration;
3231
import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError;
3332

@@ -48,7 +47,6 @@
4847
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
4948
import com.oracle.graal.python.runtime.exception.PException;
5049
import com.oracle.truffle.api.dsl.Cached;
51-
import com.oracle.truffle.api.dsl.Fallback;
5250
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
5351
import com.oracle.truffle.api.dsl.NodeFactory;
5452
import com.oracle.truffle.api.dsl.Specialization;
@@ -176,18 +174,12 @@ Object sendThrow(PGenerator self, @SuppressWarnings("unused") PythonClass typ, P
176174
}
177175
}
178176

179-
@Builtin(name = "gi_code", minNumOfArguments = 1, maxNumOfArguments = 2, isGetter = true, isSetter = true)
177+
@Builtin(name = "gi_code", fixedNumOfArguments = 1, isGetter = true)
180178
@GenerateNodeFactory
181179
public abstract static class GetCodeNode extends PythonBuiltinNode {
182-
@Specialization(guards = {"isNoValue(none)"})
183-
Object getCode(PGenerator self, @SuppressWarnings("unused") PNone none) {
180+
@Specialization
181+
Object getCode(PGenerator self) {
184182
return factory().createCode(self.getGeneratorRootNode());
185183
}
186-
187-
@SuppressWarnings("unused")
188-
@Fallback
189-
Object setCode(Object self, Object code) {
190-
throw raise(NotImplementedError, "setting gi_code");
191-
}
192184
}
193185
}

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

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,19 @@
2626

2727
package com.oracle.graal.python.builtins.objects.method;
2828

29+
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__CODE__;
30+
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__FUNC__;
31+
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__NAME__;
32+
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__SELF__;
2933
import static com.oracle.graal.python.nodes.SpecialMethodNames.__CALL__;
34+
import static com.oracle.graal.python.nodes.SpecialMethodNames.__EQ__;
3035

3136
import java.util.List;
3237

3338
import com.oracle.graal.python.builtins.Builtin;
3439
import com.oracle.graal.python.builtins.CoreFunctions;
3540
import com.oracle.graal.python.builtins.PythonBuiltins;
3641
import com.oracle.graal.python.builtins.objects.function.PKeyword;
37-
import com.oracle.graal.python.nodes.SpecialAttributeNames;
38-
import com.oracle.graal.python.nodes.SpecialMethodNames;
3942
import com.oracle.graal.python.nodes.argument.CreateArgumentsNode;
4043
import com.oracle.graal.python.nodes.call.CallDispatchNode;
4144
import com.oracle.graal.python.nodes.call.special.LookupAndCallBinaryNode;
@@ -73,7 +76,7 @@ protected Object doIt(PBuiltinMethod self, Object[] arguments, PKeyword[] keywor
7376
}
7477
}
7578

76-
@Builtin(name = "__self__", fixedNumOfArguments = 1, isGetter = true)
79+
@Builtin(name = __SELF__, fixedNumOfArguments = 1, isGetter = true)
7780
@GenerateNodeFactory
7881
public abstract static class SelfNode extends PythonBuiltinNode {
7982
@Specialization
@@ -87,7 +90,7 @@ protected Object doIt(PBuiltinMethod self) {
8790
}
8891
}
8992

90-
@Builtin(name = "__func__", fixedNumOfArguments = 1, isGetter = true)
93+
@Builtin(name = __FUNC__, fixedNumOfArguments = 1, isGetter = true)
9194
@GenerateNodeFactory
9295
public abstract static class FuncNode extends PythonBuiltinNode {
9396
@Specialization
@@ -101,27 +104,32 @@ protected Object doIt(PBuiltinMethod self) {
101104
}
102105
}
103106

104-
@Builtin(name = SpecialAttributeNames.__NAME__, fixedNumOfArguments = 1, isGetter = true)
107+
@Builtin(name = __NAME__, fixedNumOfArguments = 1, isGetter = true)
105108
@GenerateNodeFactory
106109
public abstract static class NameNode extends PythonBuiltinNode {
107110
@Specialization
108111
protected Object doIt(PMethod self,
109112
@Cached("create(__GETATTRIBUTE__)") LookupAndCallBinaryNode getCode) {
110-
return getCode.executeObject(self.getFunction(), SpecialAttributeNames.__NAME__);
113+
return getCode.executeObject(self.getFunction(), __NAME__);
114+
}
115+
116+
@Specialization
117+
protected Object doIt(PBuiltinMethod self) {
118+
return self.getName();
111119
}
112120
}
113121

114-
@Builtin(name = SpecialAttributeNames.__CODE__, fixedNumOfArguments = 1, isGetter = true)
122+
@Builtin(name = __CODE__, fixedNumOfArguments = 1, isGetter = true)
115123
@GenerateNodeFactory
116124
public abstract static class CodeNode extends PythonBuiltinNode {
117125
@Specialization
118126
protected Object doIt(PMethod self,
119127
@Cached("create(__GETATTRIBUTE__)") LookupAndCallBinaryNode getCode) {
120-
return getCode.executeObject(self.getFunction(), SpecialAttributeNames.__CODE__);
128+
return getCode.executeObject(self.getFunction(), __CODE__);
121129
}
122130
}
123131

124-
@Builtin(name = SpecialMethodNames.__EQ__, fixedNumOfArguments = 2)
132+
@Builtin(name = __EQ__, fixedNumOfArguments = 2)
125133
@GenerateNodeFactory
126134
abstract static class EqNode extends PythonBinaryBuiltinNode {
127135
@Specialization

0 commit comments

Comments
 (0)