Skip to content

Commit 9c88028

Browse files
committed
[GR-23218] Make test_descr pass - bases and dict.
PullRequest: graalpython/1080
2 parents 28ce99e + 3c00918 commit 9c88028

File tree

8 files changed

+166
-9
lines changed

8 files changed

+166
-9
lines changed

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

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -916,4 +916,44 @@ def iterate_and_update(it):
916916
assert_raises(RuntimeError, just_iterate, it)
917917

918918
d = {1:1}
919-
assert_raises(RuntimeError, iterate_and_update, d.items())
919+
assert_raises(RuntimeError, iterate_and_update, d.items())
920+
921+
def test_decorated_method_dict():
922+
def assert_bogus_dict_raises(dm):
923+
raised = False
924+
try:
925+
dm.__dict__ = 'a'
926+
except TypeError as e:
927+
raised = True
928+
assert "__dict__ must be set to a dictionary, not a 'str'" == str(e), "invalid error message"
929+
assert raised
930+
931+
class A:
932+
def f():
933+
pass
934+
935+
cm = classmethod(A.f)
936+
cm.x = 42
937+
assert cm.__dict__ == {'x': 42}
938+
cm.__dict__ = {1:1}
939+
assert cm.__dict__ == {1:1}
940+
941+
sm = staticmethod(A.f)
942+
sm.x = 42
943+
assert sm.__dict__ == {'x': 42}
944+
sm.__dict__ = {1:1}
945+
assert sm.__dict__ == {1:1}
946+
947+
assert_bogus_dict_raises(classmethod(A.f))
948+
assert_bogus_dict_raises(staticmethod(A.f))
949+
950+
def f(): pass
951+
assert_bogus_dict_raises(classmethod(f))
952+
assert_bogus_dict_raises(staticmethod(f))
953+
954+
class A:
955+
def f(self):
956+
def ff(): pass
957+
assert_bogus_dict_raises(classmethod(ff))
958+
assert_bogus_dict_raises(staticmethod(ff))
959+
A().f()

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

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2018, 2019, Oracle and/or its affiliates.
1+
# Copyright (c) 2018, 2020, Oracle and/or its affiliates.
22
# Copyright (C) 1996-2017 Python Software Foundation
33
#
44
# Licensed under the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
@@ -249,3 +249,23 @@ class C(metaclass=Meta):
249249
def __class_getitem__(cls, item):
250250
return 'from __class_getitem__'
251251
self.assertEqual(C[int], 'from metaclass')
252+
253+
class TestClassSetBases(unittest.TestCase):
254+
def test_class_set_bases(self):
255+
256+
def assert_bases(cls, bases, err, msg):
257+
raised = False
258+
try:
259+
cls.__bases__ = bases
260+
except err as e:
261+
raised = True
262+
assert msg == str(e), "invalid error message:\n expected:" + msg + "\n was:" + str(e)
263+
assert raised
264+
265+
class A(): pass
266+
class B(): pass
267+
268+
assert_bases(A, 'a', TypeError, "can only assign tuple to A.__bases__, not str")
269+
assert_bases(A, (B, 'a'), TypeError, "A.__bases__ must be tuple of classes, not 'str'")
270+
assert_bases(dict, (B,), TypeError, "can't set attributes of built-in/extension type 'dict'")
271+

graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_descr.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_buffer_inheritance
66
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_builtin_function_or_method
77
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_classic_comparisons
8+
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_classmethods
89
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_classmethods_in_c
910
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_compattr
1011
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_consistency_with_epg
@@ -28,6 +29,7 @@
2829
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_monotonicity
2930
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_mro_disagreement
3031
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_multiple_inheritance
32+
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_mutable_bases_with_failing_mro
3133
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_mutable_names
3234
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_newslots
3335
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_not_implemented
@@ -47,6 +49,7 @@
4749
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_slots_trash
4850
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_special_unbound_method_types
4951
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_specials
52+
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_staticmethods
5053
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_staticmethods_in_c
5154
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_str_of_str_subclass
5255
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_str_subclass_as_dict_key

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

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2020, 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
@@ -40,6 +40,7 @@
4040
*/
4141
package com.oracle.graal.python.builtins.objects.method;
4242

43+
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__DICT__;
4344
import static com.oracle.graal.python.nodes.SpecialMethodNames.__INIT__;
4445
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__FUNC__;
4546

@@ -48,14 +49,25 @@
4849
import com.oracle.graal.python.builtins.Builtin;
4950
import com.oracle.graal.python.builtins.CoreFunctions;
5051
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
52+
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError;
5153
import com.oracle.graal.python.builtins.PythonBuiltins;
5254
import com.oracle.graal.python.builtins.objects.PNone;
55+
import com.oracle.graal.python.builtins.objects.common.PHashingCollection;
56+
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
57+
import com.oracle.graal.python.nodes.ErrorMessages;
58+
import com.oracle.graal.python.nodes.PGuards;
5359
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
5460
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
5561
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
62+
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
63+
import com.oracle.truffle.api.CompilerDirectives;
64+
import com.oracle.truffle.api.dsl.Cached;
5665
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
66+
import com.oracle.truffle.api.dsl.ImportStatic;
5767
import com.oracle.truffle.api.dsl.NodeFactory;
5868
import com.oracle.truffle.api.dsl.Specialization;
69+
import com.oracle.truffle.api.interop.UnsupportedMessageException;
70+
import com.oracle.truffle.api.library.CachedLibrary;
5971

6072
@CoreFunctions(extendClasses = {PythonBuiltinClassType.PStaticmethod, PythonBuiltinClassType.PClassmethod})
6173
public class DecoratedMethodBuiltins extends PythonBuiltins {
@@ -83,4 +95,43 @@ protected Object func(PDecoratedMethod self) {
8395
return self.getCallable();
8496
}
8597
}
98+
99+
@Builtin(name = __DICT__, minNumOfPositionalArgs = 1, maxNumOfPositionalArgs = 2, isGetter = true, isSetter = true)
100+
@GenerateNodeFactory
101+
@ImportStatic(PGuards.class)
102+
public abstract static class DictNode extends PythonBinaryBuiltinNode {
103+
@Specialization(limit = "1")
104+
protected Object getDict(PDecoratedMethod self, @SuppressWarnings("unused") PNone mapping,
105+
@CachedLibrary("self") PythonObjectLibrary lib,
106+
@Cached PythonObjectFactory factory) {
107+
PHashingCollection dict = lib.getDict(self);
108+
if (dict == null) {
109+
dict = factory.createDictFixedStorage(self);
110+
try {
111+
lib.setDict(self, dict);
112+
} catch (UnsupportedMessageException e) {
113+
CompilerDirectives.transferToInterpreterAndInvalidate();
114+
throw new IllegalStateException(e);
115+
}
116+
}
117+
return dict;
118+
}
119+
120+
@Specialization(limit = "1")
121+
protected Object setDict(PDecoratedMethod self, PHashingCollection mapping,
122+
@CachedLibrary("self") PythonObjectLibrary lib) {
123+
try {
124+
lib.setDict(self, mapping);
125+
} catch (UnsupportedMessageException ex) {
126+
CompilerDirectives.transferToInterpreterAndInvalidate();
127+
throw new IllegalStateException(ex);
128+
}
129+
return PNone.NONE;
130+
}
131+
132+
@Specialization(guards = "!isDict(value)")
133+
protected Object setDict(@SuppressWarnings("unused") PDecoratedMethod self, Object value) {
134+
throw raise(TypeError, ErrorMessages.MUST_BE_SET_TO_S_NOT_P, __DICT__, "dictionary", value);
135+
}
136+
}
86137
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/object/ObjectBuiltins.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ PNone setClass(PythonObject self, PythonAbstractClass value,
160160
Object otherSlots = getLookupSlotsInOther().execute(value);
161161
if (otherSlots == PNone.NO_VALUE || !lib2.equals(selfSlots, otherSlots, lib2)) {
162162
errorSlotsBranch.enter();
163-
throw raise(TypeError, ErrorMessages.CLASS_ASIGMENT_D_LAYOUT_DIFFERS_FROM_S, getTypeName(value), getTypeName(lazyClass));
163+
throw raise(TypeError, ErrorMessages.CLASS_ASIGMENT_S_LAYOUT_DIFFERS_FROM_S, getTypeName(value), getTypeName(lazyClass));
164164
}
165165
}
166166
lib1.setLazyPythonClass(self, value);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeBuiltins.java

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
import com.oracle.graal.python.builtins.objects.cext.PythonNativeObject;
7171
import com.oracle.graal.python.builtins.objects.common.DynamicObjectStorage;
7272
import com.oracle.graal.python.builtins.objects.common.PHashingCollection;
73+
import com.oracle.graal.python.builtins.objects.common.SequenceNodes.GetObjectArrayNode;
7374
import com.oracle.graal.python.builtins.objects.dict.PDict;
7475
import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
7576
import com.oracle.graal.python.builtins.objects.function.PFunction;
@@ -78,8 +79,10 @@
7879
import com.oracle.graal.python.builtins.objects.mappingproxy.PMappingproxy;
7980
import com.oracle.graal.python.builtins.objects.object.PythonObject;
8081
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
82+
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
8183
import com.oracle.graal.python.builtins.objects.type.TypeBuiltinsFactory.CallNodeFactory;
8284
import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetMroNode;
85+
import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetNameNode;
8386
import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetSubclassesNode;
8487
import com.oracle.graal.python.builtins.objects.type.TypeNodesFactory.IsSameTypeNodeGen;
8588
import com.oracle.graal.python.nodes.BuiltinNames;
@@ -108,6 +111,7 @@
108111
import com.oracle.graal.python.nodes.truffle.PythonTypes;
109112
import com.oracle.graal.python.runtime.exception.PException;
110113
import com.oracle.graal.python.runtime.exception.PythonErrorType;
114+
import static com.oracle.graal.python.runtime.exception.PythonErrorType.NotImplementedError;
111115
import com.oracle.truffle.api.CompilerAsserts;
112116
import com.oracle.truffle.api.CompilerDirectives;
113117
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
@@ -536,14 +540,48 @@ Object doIt(Object args, Object kwargs) {
536540
}
537541
}
538542

539-
@Builtin(name = __BASES__, minNumOfPositionalArgs = 1, isGetter = true)
543+
@Builtin(name = __BASES__, minNumOfPositionalArgs = 1, maxNumOfPositionalArgs = 2, isGetter = true, isSetter = true)
540544
@GenerateNodeFactory
541-
abstract static class BasesNode extends PythonBuiltinNode {
545+
@ImportStatic(PGuards.class)
546+
abstract static class BasesNode extends PythonBinaryBuiltinNode {
547+
542548
@Specialization
543-
Object bases(Object self,
549+
Object getBases(Object self, @SuppressWarnings("unused") PNone value,
544550
@Cached("create()") TypeNodes.GetBaseClassesNode getBaseClassesNode) {
545551
return factory().createTuple(getBaseClassesNode.execute(self));
546552
}
553+
554+
@Specialization
555+
Object setBases(PythonClass cls, PTuple value,
556+
@Cached GetNameNode getName,
557+
@Cached GetObjectArrayNode getArray) {
558+
559+
Object[] a = getArray.execute(value);
560+
PythonAbstractClass[] baseClasses = new PythonAbstractClass[a.length];
561+
for (int i = 0; i < a.length; i++) {
562+
if (a[i] instanceof PythonAbstractClass) {
563+
baseClasses[i] = (PythonAbstractClass) a[i];
564+
} else {
565+
throw raise(TypeError, ErrorMessages.MUST_BE_TUPLE_OF_CLASSES_NOT_P, getName.execute(cls), "__bases__", a[i]);
566+
}
567+
}
568+
569+
throw raise(NotImplementedError);
570+
// return PNone.NONE;
571+
}
572+
573+
@Specialization(guards = "!isPTuple(value)")
574+
Object setObject(@SuppressWarnings("unused") PythonClass cls, @SuppressWarnings("unused") Object value,
575+
@Cached GetNameNode getName) {
576+
throw raise(TypeError, ErrorMessages.CAN_ONLY_ASSIGN_S_TO_S_S_NOT_P, "tuple", getName.execute(cls), "__bases__", value);
577+
}
578+
579+
@Specialization
580+
Object setBuiltin(@SuppressWarnings("unused") PythonBuiltinClass cls, @SuppressWarnings("unused") Object value,
581+
@Cached GetNameNode getName) {
582+
throw raise(TypeError, ErrorMessages.CANT_SET_ATTRIBUTES_OF_TYPE_S, getName.execute(cls));
583+
}
584+
547585
}
548586

549587
@Builtin(name = __BASE__, minNumOfPositionalArgs = 1, isGetter = true)

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ public abstract class ErrorMessages {
9595
public static final String CALLING_ARG_CONVERTER_FAIL_UNEXPECTED_RETURN = "calling argument converter failed; unexpected return value %s";
9696
public static final String CALLING_NATIVE_FUNC_EXPECTED_ARGS = "Calling native function %s expected %d arguments but got %d.";
9797
public static final String CALLING_NATIVE_FUNC_FAILED = "Calling native function %s failed: %m";
98+
public static final String CAN_ONLY_ASSIGN_S_TO_S_S_NOT_P = "can only assign %s to %s.%s, not %p";
9899
public static final String CAN_ONLY_CONCAT_S_NOT_P_TO_S = "can only concatenate %s (not \"%p\") to %s";
99100
public static final String CAN_ONLY_JOIN_ITERABLE = "can only join an iterable";
100101
public static final String CANNOT_ASSIGN_TO = "cannot assign to %s";
@@ -146,9 +147,10 @@ public abstract class ErrorMessages {
146147
public static final String CHARACTER_MAPPING_MUST_BE_IN_RANGE = "character mapping must be in range(0x%s)";
147148
public static final String CHARACTER_MAPPING_MUST_RETURN_INT_NONE_OR_STR = "character mapping must return integer, None or str";
148149
public static final String CHR_DOES_NOT_SUPPORT = "chr does not support PInt ";
149-
public static final String CLASS_ASIGMENT_D_LAYOUT_DIFFERS_FROM_S = "__class__ assignment: '%s' object layout differs from '%s'";
150+
public static final String CLASS_ASIGMENT_S_LAYOUT_DIFFERS_FROM_S = "__class__ assignment: '%s' object layout differs from '%s'";
150151
public static final String CLASS_ASSIGMENT_ONLY_SUPPORTED_FOR_HEAP_TYPES_OR_MODTYPE_SUBCLASSES = "__class__ assignment only supported for heap types or ModuleType subclasses, not '%p'";
151152
public static final String CLASS_MUST_BE_SET_TO_CLASS = "__class__ must be set to a class, not '%p' object";
153+
public static final String MUST_BE_SET_TO_S_NOT_P = "%s must be set to a %s, not a '%p'";
152154
public static final String CLASSPATH_ARG_MUST_BE_STRING = "classpath argument %d must be string, not %p";
153155
public static final String CODE_OBJ_NO_FREE_VARIABLES = "code object passed to %s may not contain free variables";
154156
public static final String COMPILE_MUST_BE = "compile() mode must be 'exec', 'eval' or 'single'";
@@ -331,6 +333,7 @@ public abstract class ErrorMessages {
331333
public static final String MUST_BE_SET_TO_STR_OBJ = "%s must be set to a string object";
332334
public static final String MUST_BE_STRINGS = "%s must be strings";
333335
public static final String MUST_BE_STRINGS_NOT_P = "%s must be strings, not %p";
336+
public static final String MUST_BE_TUPLE_OF_CLASSES_NOT_P = "%s.%s must be tuple of classes, not '%p'";
334337
public static final String MUST_SPECIFY_FILTERS = "Must specify filters for FORMAT_RAW";
335338
public static final String MUTATED_DURING_UPDATE = "%s mutated during update";
336339
public static final String NAME_IS_ASSIGNED_BEFORE_GLOBAL = "name '%s' is assigned to before global declaration";

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import com.oracle.graal.python.builtins.objects.common.PHashingCollection;
5252
import com.oracle.graal.python.builtins.objects.exception.PBaseException;
5353
import com.oracle.graal.python.builtins.objects.function.PFunction;
54+
import com.oracle.graal.python.builtins.objects.method.PDecoratedMethod;
5455
import com.oracle.graal.python.builtins.objects.method.PMethod;
5556
import com.oracle.graal.python.builtins.objects.module.PythonModule;
5657
import com.oracle.graal.python.builtins.objects.object.PythonObject;
@@ -92,7 +93,8 @@ public static WriteAttributeToObjectNode getUncached() {
9293
}
9394

9495
protected static boolean isAttrWritable(IsBuiltinClassProfile exactBuiltinInstanceProfile, PythonObject self, Object key) {
95-
if (isHiddenKey(key) || self instanceof PythonManagedClass || self instanceof PFunction || self instanceof PMethod || self instanceof PythonModule || self instanceof PBaseException) {
96+
if (isHiddenKey(key) || self instanceof PythonManagedClass || self instanceof PFunction || self instanceof PMethod || self instanceof PDecoratedMethod || self instanceof PythonModule ||
97+
self instanceof PBaseException) {
9698
return true;
9799
}
98100
return !exactBuiltinInstanceProfile.profileIsAnyBuiltinObject(self);

0 commit comments

Comments
 (0)