Skip to content

Commit ac1dcf7

Browse files
committed
[GR-18744] [GR-18756] [GR-16816] [GR-18813] [GR-18788] Various bug fixes.
PullRequest: graalpython/685
2 parents 82977ce + 66a8a83 commit ac1dcf7

File tree

34 files changed

+742
-189
lines changed

34 files changed

+742
-189
lines changed

graalpython/com.oracle.graal.python.cext/include/Python.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@
122122
#include "weakrefobject.h"
123123
#include "sysmodule.h"
124124
#include "fileutils.h"
125+
#include "pystrtod.h"
125126

126127
// TODO: we must extend the refcounting behavior to support handles to managed objects
127128
#undef Py_DECREF
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/* Copyright (c) 2019, Oracle and/or its affiliates.
2+
* Copyright (C) 1996-2017 Python Software Foundation
3+
*
4+
* Licensed under the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
5+
*/
6+
7+
#ifndef Py_STRTOD_H
8+
#define Py_STRTOD_H
9+
10+
#ifdef __cplusplus
11+
extern "C" {
12+
#endif
13+
14+
15+
PyAPI_FUNC(double) PyOS_string_to_double(const char *str,
16+
char **endptr,
17+
PyObject *overflow_exception);
18+
19+
/* The caller is responsible for calling PyMem_Free to free the buffer
20+
that's is returned. */
21+
PyAPI_FUNC(char *) PyOS_double_to_string(double val,
22+
char format_code,
23+
int precision,
24+
int flags,
25+
int *type);
26+
27+
#ifndef Py_LIMITED_API
28+
PyAPI_FUNC(PyObject *) _Py_string_to_number_with_underscores(
29+
const char *str, Py_ssize_t len, const char *what, PyObject *obj, void *arg,
30+
PyObject *(*innerfunc)(const char *, Py_ssize_t, void *));
31+
32+
PyAPI_FUNC(double) _Py_parse_inf_or_nan(const char *p, char **endptr);
33+
#endif
34+
35+
36+
/* PyOS_double_to_string's "flags" parameter can be set to 0 or more of: */
37+
#define Py_DTSF_SIGN 0x01 /* always add the sign */
38+
#define Py_DTSF_ADD_DOT_0 0x02 /* if the result is an integer add ".0" */
39+
#define Py_DTSF_ALT 0x04 /* "alternate" formatting. it's format_code
40+
specific */
41+
42+
/* PyOS_double_to_string's "type", if non-NULL, will be set to one of: */
43+
#define Py_DTST_FINITE 0
44+
#define Py_DTST_INFINITE 1
45+
#define Py_DTST_NAN 2
46+
47+
#ifdef __cplusplus
48+
}
49+
#endif
50+
51+
#endif /* !Py_STRTOD_H */

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,19 @@ double PyOS_string_to_double(const char *s, char **endptr, PyObject *overflow_ex
5353
}
5454
return result;
5555
}
56+
57+
/* translation macro to be independent of changes in 'pystrtod.h' */
58+
#define TRANSLATE_TYPE(__tc__) ((__tc__) == 0 ? Py_DTST_FINITE : ((__tc__) == 1 ? Py_DTST_INFINITE : Py_DTST_NAN))
59+
60+
UPCALL_ID(PyTruffle_OS_DoubleToString);
61+
char * PyOS_double_to_string(double val, char format_code, int precision, int flags, int *type) {
62+
char* result = NULL;
63+
PyObject* resultTuple = UPCALL_CEXT_O(_jls_PyTruffle_OS_DoubleToString, val, (int32_t)format_code, precision, flags);
64+
if (resultTuple != NULL) {
65+
result = (char *) PyTuple_GetItem(resultTuple, 0);
66+
if (type != NULL) {
67+
*type = TRANSLATE_TYPE(as_int(PyTuple_GetItem(resultTuple, 1)));
68+
}
69+
}
70+
return result;
71+
}

graalpython/com.oracle.graal.python.test/src/tests/cpyext/__init__.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -151,15 +151,14 @@ def file_not_empty(path):
151151
return NULL;
152152
}}
153153
154-
if (strlen("{argspec}") > 0) {{
155-
if (!PyArg_ParseTuple(___arg, "{argspec}", {derefargumentnames})) {{
156-
return NULL;
157-
}}
158-
}}
159154
#ifdef SINGLEARG
160-
else {{
161-
{singleargumentname} = ___arg;
155+
{singleargumentname} = ___arg;
156+
#else
157+
#ifndef NOARGS
158+
if (!PyArg_ParseTuple(___arg, "{argspec}", {derefargumentnames})) {{
159+
return NULL;
162160
}}
161+
#endif
163162
#endif
164163
165164
return Py_BuildValue("{resultspec}", {callfunction}({argumentnames}));
@@ -326,10 +325,12 @@ def create_module(self, name=None):
326325

327326
self._insert(fargs, "argumentdeclarations", ";".join(fargs["parseargs"]))
328327
self._insert(fargs, "argumentnames", ", ".join(arg.rpartition(" ")[2] for arg in fargs["arguments"]))
329-
self._insert(fargs, "singleargumentname", fargs["arguments"][0].rpartition(" ")[2])
328+
self._insert(fargs, "singleargumentname", fargs["arguments"][0].rpartition(" ")[2] if fargs["arguments"] else "")
330329
self._insert(fargs, "derefargumentnames", ", ".join("&" + arg.rpartition(" ")[2].partition("=")[0] for arg in fargs["arguments"]))
331330
self._insert(fargs, "callfunction", fargs["capifunction"])
332-
if len(fargs["argspec"]) == 0:
331+
if len(fargs["argspec"]) == 0 and len(fargs["arguments"]) == 0:
332+
fargs["defines"] = "#define NOARGS"
333+
elif len(fargs["argspec"]) == 0:
333334
fargs["defines"] = "#define SINGLEARG"
334335
else:
335336
fargs["defines"] = ""

graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_misc.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,27 @@
3939

4040
import sys
4141
from . import CPyExtTestCase, CPyExtFunction, CPyExtFunctionOutVars, unhandled_error_compare, GRAALPYTHON
42+
import builtins
4243
__dir__ = __file__.rpartition("/")[0]
4344

45+
__global_builtins_dict = builtins.__dict__
46+
4447

4548
def _reference_importmodule(args):
4649
return __import__(args[0], fromlist=["*"])
4750

4851

52+
def _reference_format_float(args):
53+
val, format_spec, prec = args
54+
if format_spec == b'r':
55+
return repr(val)
56+
return float(val).__format__("." + str(prec) + format_spec.decode())
57+
58+
59+
def _reference_builtins(args):
60+
return type(__global_builtins_dict)
61+
62+
4963
class TestMisc(CPyExtTestCase):
5064

5165
def compile_module(self, name):
@@ -212,3 +226,42 @@ def compile_module(self, name):
212226
arguments=["PyObject* pyVal", "PyObject* fun"],
213227
cmpfunc=unhandled_error_compare
214228
)
229+
230+
test_PyOS_double_to_string = CPyExtFunction(
231+
_reference_format_float,
232+
lambda: (
233+
(1.2, b"f", 2),
234+
(float('nan'), b"f", 2),
235+
(1.23456789, b"f", 2),
236+
(123.456789, b"f", 6),
237+
(123.456789, b"e", 6),
238+
(123.456789, b"r", 0),
239+
),
240+
code="""
241+
char* wrap_PyOS_double_to_string(double val, char format, int prec) {
242+
return PyOS_double_to_string(val, format, prec, 0, NULL);
243+
}
244+
""",
245+
resultspec="s",
246+
argspec="dci",
247+
arguments=["double val", "char format", "int prec"],
248+
callfunction="wrap_PyOS_double_to_string",
249+
cmpfunc=unhandled_error_compare
250+
)
251+
252+
test_PyEval_GetBuiltins = CPyExtFunction(
253+
_reference_builtins,
254+
lambda: (
255+
tuple(),
256+
),
257+
code="""
258+
PyObject* wrap_PyEval_GetBuiltins() {
259+
return Py_TYPE(PyEval_GetBuiltins());
260+
}
261+
""",
262+
resultspec="O",
263+
argspec="",
264+
arguments=[],
265+
callfunction="wrap_PyEval_GetBuiltins",
266+
cmpfunc=unhandled_error_compare
267+
)

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,34 @@ def test_setitem():
185185
pass
186186

187187

188+
class BaseGetSlice:
189+
def assertEqualWithType(self, a, b):
190+
self.assertEqual(a, b)
191+
self.assertEqual(type(a), type(b))
192+
193+
def test_getslice(self):
194+
# whole sequence
195+
b = self.type2test(b"hello")
196+
self.assertEqualWithType(b[:], self.type2test(b"hello"))
197+
198+
# whole same length as slice
199+
b = self.type2test(b"hellohellohello")
200+
self.assertEqualWithType(b[5:10], self.type2test(b"hello"))
201+
202+
# shrink
203+
b = self.type2test(b"hellohellohello")
204+
self.assertEqualWithType(b[:10], self.type2test(b"hellohello"))
205+
206+
# extend
207+
b = self.type2test(b"hellohelloworld")
208+
self.assertEqualWithType(b[5:], self.type2test(b"helloworld"))
209+
210+
class BytesGetSliceTest(BaseGetSlice, unittest.TestCase):
211+
type2test = bytes
212+
213+
class ByteArrayGetSliceTest(BaseGetSlice, unittest.TestCase):
214+
type2test = bytearray
215+
188216
def test_setslice():
189217
# whole sequence
190218
b = bytearray(b"hello")
@@ -646,6 +674,7 @@ def test_add_mv_to_bytes():
646674
mv = memoryview(b'world')
647675
b += mv
648676
assert b == b'hello world'
677+
assert type(b) == bytes
649678

650679
def test_add_mv_to_bytearray():
651680
ba = bytearray(b'hello ')

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,18 @@ def test_basic(self):
5454
l[0] = "hello"
5555
self.assertEqual(l, ["hello", 1, 2, 3, 4])
5656

57+
def test_literal(self):
58+
self.assertEqual([1,2,3], [*[1,2,3]])
59+
self.assertEqual([1,2,3], [*(1,2,3)])
60+
self.assertEqual([1,2,3,4,5,6], [*(1,2,3), *(4,5,6)])
61+
62+
# this will certainly create a list where the capacity of the storage is not exhausted, i.e., 'length < cap',
63+
# and so the storage contains null elements
64+
l = []
65+
for c in "abcdefghijk":
66+
l.append(c)
67+
self.assertEqual(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k'], [*l])
68+
5769
def test_truth(self):
5870
super().test_truth()
5971
self.assertTrue(not [])

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

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
1+
# Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
22
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
33
#
44
# The Universal Permissive License (UPL), Version 1.0
@@ -72,6 +72,22 @@ def prop_x(self):
7272
del self._x
7373

7474

75+
class X(object):
76+
@property
77+
def prop_x(self):
78+
return self._prop_x
79+
80+
@prop_x.setter
81+
def prop_x(self, new_val):
82+
self._prop_x = new_val
83+
return new_val
84+
85+
class Y(X):
86+
@X.prop_x.setter
87+
def prop_x(self, ax):
88+
X.prop_x.fset(self, ax)
89+
90+
7591
def test_properties():
7692
c = C(10)
7793
assert c.prop_x == 10
@@ -96,3 +112,5 @@ def test_properties():
96112
except AttributeError:
97113
not_found = True
98114
assert not_found
115+
116+
assert X.prop_x is not Y.prop_x

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

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -187,13 +187,23 @@ def test_sub_and_super():
187187
assert not set('cbs').issuperset('a')
188188

189189

190-
def test_superset_list():
191-
set = {1, 2, 3, 4}
192-
list = [1, 2, 3, 4]
193-
visited= False
194-
if set.issuperset(list):
195-
visited = True
196-
assert visited
190+
def test_superset_subset():
191+
l = [1, 2, 3, 4]
192+
s = set(l)
193+
t = tuple(l)
194+
assert s.issuperset(s)
195+
assert s.issuperset(l)
196+
assert s.issuperset(t)
197+
assert s >= s
198+
assert_raises(TypeError, lambda: s >= l)
199+
assert_raises(TypeError, lambda: s >= t)
200+
201+
assert s.issubset(s)
202+
assert s.issubset(l)
203+
assert s.issubset(t)
204+
assert s <= s
205+
assert_raises(TypeError, lambda: s <= l)
206+
assert_raises(TypeError, lambda: s <= t)
197207

198208

199209
def test_intersection():
@@ -293,3 +303,13 @@ def test_set_delete():
293303
assert s == {'a', 'b', 'c'}
294304
s.discard('c')
295305
assert s == {'a', 'b'}
306+
307+
308+
def test_literal():
309+
d = {"a": 1, "b": 2, "c": 3}
310+
e = {"uff": "foo"}
311+
assert {*d, *e} == {"a", "b", "c", "uff"}
312+
313+
d = {}
314+
assert {*d} == set()
315+

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ def test_constructors(self):
2222
self.assertEqual(tuple(''), ())
2323
self.assertEqual(tuple('spam'), ('s', 'p', 'a', 'm'))
2424

25+
def test_literal(self):
26+
self.assertEqual((1,2,3), (*[1,2,3],))
27+
2528
def test_truth(self):
2629
super().test_truth()
2730
self.assertTrue(not ())

0 commit comments

Comments
 (0)