Skip to content

Commit d5f83db

Browse files
committed
[GR-11913] Support pickle module.
PullRequest: graalpython/215
2 parents 4a95680 + 5503701 commit d5f83db

File tree

25 files changed

+549
-108
lines changed

25 files changed

+549
-108
lines changed

graalpython/com.oracle.graal.python.cext/src/object.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,12 @@ PyObject* PyObject_CallMethod(PyObject* object, const char* method, const char*
243243
return UPCALL_CEXT_O(_jls_PyObject_CallMethod, native_to_java(object), polyglot_from_string(method, SRC_CS), native_to_java(args));
244244
}
245245

246+
PyObject* _PyObject_CallMethod_SizeT(PyObject* object, const char* method, const char* fmt, ...) {
247+
PyObject* args;
248+
CALL_WITH_VARARGS(args, Py_BuildValue, 3, fmt);
249+
return UPCALL_CEXT_O(_jls_PyObject_CallMethod, native_to_java(object), polyglot_from_string(method, SRC_CS), native_to_java(args));
250+
}
251+
246252
UPCALL_ID(type);
247253
PyObject* PyObject_Type(PyObject* obj) {
248254
return UPCALL_O(PY_BUILTIN, _jls_type, native_to_java(obj));

graalpython/com.oracle.graal.python.cext/src/typeobject.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -232,10 +232,7 @@ int PyType_Ready(PyTypeObject* cls) {
232232
PyDict_SetItemString(native_members, "tp_name", polyglot_from_string(cls->tp_name, SRC_CS));
233233
PyDict_SetItemString(native_members, "tp_doc", polyglot_from_string(cls->tp_doc ? cls->tp_doc : "", SRC_CS));
234234
PyDict_SetItemString(native_members, "tp_basicsize", PyLong_FromSsize_t(cls->tp_basicsize));
235-
const char* lastDot = strrchr(cls->tp_name, '.');
236-
if (lastDot) {
237-
PyDict_SetItemString(native_members, "__module__", polyglot_from_string(lastDot + 1, SRC_CS));
238-
}
235+
const char* class_name = cls->tp_name;
239236
PyTypeObject* javacls = polyglot_invoke(PY_TRUFFLE_CEXT,
240237
"PyType_Ready",
241238
// no conversion of cls here, because we

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ def __round__(x, n):
9696
def test_create(self):
9797
assert float(99) == 99
9898
assert float(999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999) == 1e+132
99+
assert float(b"0.001") == 0.001
100+
assert float("0.001") == 0.001
99101

100102
def test_hex(self):
101103
data = [

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.test/src/tests/test_metaclass.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,17 @@ def __init__(self, a, b):
128128
assert len(global_log) == 4
129129
assert global_log[2] == ['__call__', MyClass, (1, 2), {}]
130130
assert global_log[3] == ['MyKlass object', 1, 2]
131+
132+
133+
class A:
134+
class B:
135+
pass
136+
137+
138+
def test_nested_class():
139+
assert A.__name__ == "A"
140+
assert A.__qualname__ == "A"
141+
assert A.__module__ == __name__
142+
assert A.B.__name__ == "B"
143+
assert A.B.__qualname__ == "A.B"
144+
assert A.B.__module__ == __name__
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
2+
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3+
#
4+
# The Universal Permissive License (UPL), Version 1.0
5+
#
6+
# Subject to the condition set forth below, permission is hereby granted to any
7+
# person obtaining a copy of this software, associated documentation and/or
8+
# data (collectively the "Software"), free of charge and under any and all
9+
# copyright rights in the Software, and any and all patent rights owned or
10+
# freely licensable by each licensor hereunder covering either (i) the
11+
# unmodified Software as contributed to or provided by such licensor, or (ii)
12+
# the Larger Works (as defined below), to deal in both
13+
#
14+
# (a) the Software, and
15+
#
16+
# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
17+
# one is included with the Software each a "Larger Work" to which the Software
18+
# is contributed by such licensors),
19+
#
20+
# without restriction, including without limitation the rights to copy, create
21+
# derivative works of, display, perform, and distribute the Software and make,
22+
# use, sell, offer for sale, import, export, have made, and have sold the
23+
# Software and the Larger Work(s), and to sublicense the foregoing rights on
24+
# either these or other terms.
25+
#
26+
# This license is subject to the following condition:
27+
#
28+
# The above copyright notice and either this complete permission notice or at a
29+
# minimum a reference to the UPL must be included in all copies or substantial
30+
# portions of the Software.
31+
#
32+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38+
# SOFTWARE.
39+
40+
import unittest
41+
import pickle
42+
43+
class TestPickle(unittest.TestCase):
44+
45+
def test_builtin(self):
46+
self.pickle_unpickle(len)
47+
import sys
48+
self.pickle_unpickle(sys.getrecursionlimit)
49+
50+
def test_local(self):
51+
self.pickle_unpickle("test")
52+
myvar = 10
53+
self.pickle_unpickle(myvar)
54+
55+
def pickle_unpickle(self, obj):
56+
b_obj = pickle.dumps(obj, protocol=0)
57+
r_obj = pickle.loads(b_obj)
58+
self.assertEqual(r_obj, obj)
59+
60+
if __name__ == '__main__':
61+
unittest.main()

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@ public String[] builtinModuleNames() {
425425
return builtinModules.keySet().toArray(new String[0]);
426426
}
427427

428+
@Override
428429
public PythonModule getBuiltins() {
429430
return builtinsModule;
430431
}

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

Lines changed: 53 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
import com.oracle.graal.python.builtins.objects.PEllipsis;
6868
import com.oracle.graal.python.builtins.objects.PNone;
6969
import com.oracle.graal.python.builtins.objects.PNotImplemented;
70+
import com.oracle.graal.python.builtins.objects.bytes.BytesNodes;
7071
import com.oracle.graal.python.builtins.objects.bytes.BytesUtils;
7172
import com.oracle.graal.python.builtins.objects.bytes.PBytes;
7273
import com.oracle.graal.python.builtins.objects.bytes.PIBytesLike;
@@ -558,6 +559,8 @@ public Object reversed(PythonClass cls, Object sequence,
558559
@Builtin(name = FLOAT, minNumOfPositionalArgs = 1, maxNumOfPositionalArgs = 2, constructsClass = PythonBuiltinClassType.PFloat)
559560
@GenerateNodeFactory
560561
public abstract static class FloatNode extends PythonBuiltinNode {
562+
@Child private BytesNodes.ToBytesNode toByteArrayNode;
563+
561564
private final ConditionProfile isPrimitiveProfile = ConditionProfile.createBinaryProfile();
562565

563566
protected boolean isPrimitiveFloat(Object cls) {
@@ -617,6 +620,16 @@ public Object floatFromString(PythonClass cls, String arg) {
617620
return factory().createFloat(cls, value);
618621
}
619622

623+
@Specialization(guards = "!isNativeClass(cls)")
624+
@TruffleBoundary
625+
public Object floatFromBytes(PythonClass cls, PIBytesLike arg) {
626+
double value = convertStringToDouble(new String(getByteArray(arg)));
627+
if (isPrimitiveFloat(cls)) {
628+
return value;
629+
}
630+
return factory().createFloat(cls, value);
631+
}
632+
620633
// Taken from Jython PyString's atof() method
621634
// The last statement throw Py.ValueError is modified
622635
@TruffleBoundary
@@ -722,6 +735,14 @@ Object doPythonObject(PythonNativeClass cls, Object obj,
722735
public Object floatFromObject(@SuppressWarnings("unused") Object cls, Object arg) {
723736
throw raise(TypeError, "can't convert %s to float", arg.getClass().getSimpleName());
724737
}
738+
739+
private byte[] getByteArray(PIBytesLike pByteArray) {
740+
if (toByteArrayNode == null) {
741+
CompilerDirectives.transferToInterpreterAndInvalidate();
742+
toByteArrayNode = insert(BytesNodes.ToBytesNode.create());
743+
}
744+
return toByteArrayNode.execute(pByteArray);
745+
}
725746
}
726747

727748
// frozenset([iterable])
@@ -780,7 +801,7 @@ private HashingCollectionNodes.SetItemNode getSetItemNode() {
780801
@GenerateNodeFactory
781802
public abstract static class IntNode extends PythonBuiltinNode {
782803

783-
@Child private SequenceStorageNodes.ToByteArrayNode toByteArrayNode;
804+
@Child private BytesNodes.ToBytesNode toByteArrayNode;
784805

785806
@TruffleBoundary(transferToInterpreterOnException = false)
786807
private Object stringToInt(String num, int base) {
@@ -980,30 +1001,32 @@ public Object createInt(PythonClass cls, String arg, @SuppressWarnings("unused")
9801001
@Specialization(guards = "isPrimitiveInt(cls)", rewriteOn = NumberFormatException.class)
9811002
@TruffleBoundary
9821003
int parseInt(Object cls, PIBytesLike arg, int keywordArg) throws NumberFormatException {
983-
return parseInt(cls, new String(getByteArray(arg)), keywordArg);
1004+
return parseInt(cls, toString(arg), keywordArg);
9841005
}
9851006

9861007
@Specialization(guards = "isPrimitiveInt(cls)", rewriteOn = NumberFormatException.class)
9871008
@TruffleBoundary
9881009
long parseLong(Object cls, PIBytesLike arg, int keywordArg) throws NumberFormatException {
989-
return parseLong(cls, new String(getByteArray(arg)), keywordArg);
1010+
return parseLong(cls, toString(arg), keywordArg);
9901011
}
9911012

992-
@Specialization(rewriteOn = NumberFormatException.class)
993-
@TruffleBoundary
994-
Object parseBytes(PythonClass cls, PIBytesLike arg, int base) {
995-
return parsePInt(cls, new String(getByteArray(arg)), base);
996-
}
997-
998-
@Specialization(replaces = "parseBytes")
999-
Object parseBytesError(PythonClass cls, PIBytesLike arg, int base) {
1013+
@Specialization
1014+
Object parseBytesError(PythonClass cls, PIBytesLike arg, int base,
1015+
@Cached("create()") BranchProfile errorProfile) {
10001016
try {
1001-
return parseBytes(cls, arg, base);
1017+
return parsePInt(cls, toString(arg), base);
10021018
} catch (NumberFormatException e) {
1019+
errorProfile.enter();
10031020
throw raise(ValueError, "invalid literal for int() with base %s: %s", base, arg);
10041021
}
10051022
}
10061023

1024+
@Specialization(guards = "isNoValue(base)")
1025+
Object parseBytesError(PythonClass cls, PIBytesLike arg, @SuppressWarnings("unused") PNone base,
1026+
@Cached("create()") BranchProfile errorProfile) {
1027+
return parseBytesError(cls, arg, 10, errorProfile);
1028+
}
1029+
10071030
@Specialization(guards = "isPrimitiveInt(cls)", rewriteOn = NumberFormatException.class)
10081031
int parseInt(Object cls, PString arg, int keywordArg) throws NumberFormatException {
10091032
return parseInt(cls, arg.getValue(), keywordArg);
@@ -1020,6 +1043,11 @@ Object parsePInt(PythonClass cls, PString arg, int keywordArg) {
10201043
return parsePInt(cls, arg.getValue(), keywordArg);
10211044
}
10221045

1046+
@Specialization(guards = "isNoValue(base)")
1047+
Object parsePInt(PythonClass cls, PString arg, PNone base) {
1048+
return createInt(cls, arg.getValue(), base);
1049+
}
1050+
10231051
@Specialization(guards = "isPrimitiveInt(cls)", rewriteOn = NumberFormatException.class)
10241052
@TruffleBoundary
10251053
int parseInt(@SuppressWarnings("unused") Object cls, String arg, int keywordArg) throws NumberFormatException {
@@ -1078,7 +1106,7 @@ Object fail(PythonClass cls, Object arg, Object keywordArg) {
10781106
throw raise(TypeError, "int() can't convert non-string with explicit base");
10791107
}
10801108

1081-
@Specialization(guards = {"isNoValue(keywordArg)", "!isNoValue(obj)"})
1109+
@Specialization(guards = {"isNoValue(keywordArg)", "!isNoValue(obj)", "!isHandledType(obj)"})
10821110
public Object createInt(PythonClass cls, Object obj, PNone keywordArg,
10831111
@Cached("create(__INT__)") LookupAndCallUnaryNode callIntNode,
10841112
@Cached("create(__TRUNC__)") LookupAndCallUnaryNode callTruncNode,
@@ -1113,12 +1141,21 @@ public Object createInt(PythonClass cls, Object obj, PNone keywordArg,
11131141
}
11141142
}
11151143

1116-
private byte[] getByteArray(PIBytesLike pByteArray) {
1144+
protected static boolean isHandledType(Object obj) {
1145+
return PGuards.isInteger(obj) || obj instanceof Double || obj instanceof Boolean || PGuards.isString(obj) || PGuards.isBytes(obj);
1146+
}
1147+
1148+
private String toString(PIBytesLike pByteArray) {
11171149
if (toByteArrayNode == null) {
11181150
CompilerDirectives.transferToInterpreterAndInvalidate();
1119-
toByteArrayNode = insert(SequenceStorageNodes.ToByteArrayNode.create());
1151+
toByteArrayNode = insert(BytesNodes.ToBytesNode.create());
11201152
}
1121-
return toByteArrayNode.execute(pByteArray.getSequenceStorage());
1153+
return toString(toByteArrayNode.execute(pByteArray));
1154+
}
1155+
1156+
@TruffleBoundary
1157+
private static String toString(byte[] barr) {
1158+
return new String(barr);
11221159
}
11231160

11241161
}

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
import com.oracle.graal.python.builtins.objects.PNotImplemented;
8484
import com.oracle.graal.python.builtins.objects.bytes.BytesNodes;
8585
import com.oracle.graal.python.builtins.objects.bytes.PBytes;
86+
import com.oracle.graal.python.builtins.objects.bytes.PIBytesLike;
8687
import com.oracle.graal.python.builtins.objects.cell.PCell;
8788
import com.oracle.graal.python.builtins.objects.code.PCode;
8889
import com.oracle.graal.python.builtins.objects.common.HashingCollectionNodes;
@@ -456,6 +457,7 @@ private static BigInteger[] divideAndRemainder(PInt a, PInt b) {
456457
public abstract static class EvalNode extends PythonBuiltinNode {
457458
@Child private GetItemNode getNameNode = GetItemNode.create();
458459
@Child private ReadCallerFrameNode readCallerFrameNode = ReadCallerFrameNode.create();
460+
@Child private SequenceStorageNodes.ToByteArrayNode toByteArrayNode;
459461

460462
@Specialization
461463
public Object eval(VirtualFrame frame, String expression, @SuppressWarnings("unused") PNone globals, @SuppressWarnings("unused") PNone locals) {
@@ -515,6 +517,39 @@ public Object eval(VirtualFrame frame, PCode code, @SuppressWarnings("unused") P
515517
return evalExpression(code, callerGlobals, locals, callerClosure);
516518
}
517519

520+
@Specialization
521+
public Object eval(VirtualFrame frame, PBytes expression, PNone globals, PNone locals) {
522+
return eval(frame, getString(expression), globals, locals);
523+
}
524+
525+
@Specialization
526+
public Object eval(VirtualFrame frame, PBytes expression, PythonObject globals, PNone locals) {
527+
return eval(frame, getString(expression), globals, locals);
528+
}
529+
530+
@Specialization
531+
public Object eval(VirtualFrame frame, PBytes expression, PythonObject globals, PythonObject locals) {
532+
return eval(frame, getString(expression), globals, locals);
533+
}
534+
535+
@Specialization
536+
public Object eval(VirtualFrame frame, PBytes expression, PNone globals, PythonObject locals) {
537+
return eval(frame, getString(expression), globals, locals);
538+
}
539+
540+
@TruffleBoundary
541+
private String getString(PBytes expression) {
542+
return new String(getByteArray(expression));
543+
}
544+
545+
private byte[] getByteArray(PIBytesLike pByteArray) {
546+
if (toByteArrayNode == null) {
547+
CompilerDirectives.transferToInterpreterAndInvalidate();
548+
toByteArrayNode = insert(SequenceStorageNodes.ToByteArrayNode.create());
549+
}
550+
return toByteArrayNode.execute(pByteArray.getSequenceStorage());
551+
}
552+
518553
@TruffleBoundary
519554
private static Object evalExpression(PCode code, PythonObject globals, PythonObject locals, PCell[] closure) {
520555
RootNode root = code.getRootNode();

0 commit comments

Comments
 (0)