Skip to content

Commit 1c26308

Browse files
committed
Support native floats in more builtins
1 parent 6541950 commit 1c26308

File tree

17 files changed

+408
-1072
lines changed

17 files changed

+408
-1072
lines changed

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

Lines changed: 107 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,15 @@
3636
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3737
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3838
# SOFTWARE.
39+
import math
40+
41+
from . import CPyExtType, CPyExtTestCase, CPyExtFunction, CPyExtFunctionOutVars, unhandled_error_compare, \
42+
is_native_object
3943

40-
import sys
41-
from . import CPyExtType, CPyExtTestCase, CPyExtFunction, CPyExtFunctionOutVars, unhandled_error_compare, GRAALPYTHON
4244
__dir__ = __file__.rpartition("/")[0]
4345

4446

4547
def _float_compare(x, y):
46-
4748
def isNan(x):
4849
return isinstance(x, float) and x != x
4950

@@ -77,6 +78,17 @@ def __float__(self):
7778
return 2.71828
7879

7980

81+
NativeFloatSubclass = CPyExtType(
82+
'NativeFloatSubclass',
83+
'',
84+
struct_base='PyFloatObject base',
85+
tp_base="&PyFloat_Type",
86+
tp_new='0',
87+
tp_alloc='0',
88+
tp_free='0',
89+
)
90+
91+
8092
class TestPyFloat(CPyExtTestCase):
8193

8294
def compile_module(self, name):
@@ -185,39 +197,107 @@ def compile_module(self, name):
185197
cmpfunc=unhandled_error_compare
186198
)
187199

200+
188201
class TestPyOSDouble:
189202
def test_PyOS_double_to_string(self):
190-
TestPyOS_Double_To_String = CPyExtType("TestPyOS_Double_To_String",
191-
'''
192-
static PyObject* testPyOS_D_to_Str(PyObject* self, PyObject *pyval) {
193-
double val = PyFloat_AsDouble(pyval);
194-
char *str = PyOS_double_to_string(val, 'f', 6, 0x2, NULL);
195-
return PyUnicode_FromString(str);
196-
}
197-
''',
198-
tp_methods='{"PyOS_double_to_string_test", (PyCFunction)testPyOS_D_to_Str, METH_O, ""}',
199-
)
203+
TestPyOS_Double_To_String = CPyExtType(
204+
"TestPyOS_Double_To_String",
205+
'''
206+
static PyObject* testPyOS_D_to_Str(PyObject* self, PyObject *pyval) {
207+
double val = PyFloat_AsDouble(pyval);
208+
char *str = PyOS_double_to_string(val, 'f', 6, 0x2, NULL);
209+
return PyUnicode_FromString(str);
210+
}
211+
''',
212+
tp_methods='{"PyOS_double_to_string_test", (PyCFunction)testPyOS_D_to_Str, METH_O, ""}',
213+
)
200214
tester = TestPyOS_Double_To_String()
201215
assert tester.PyOS_double_to_string_test(150.604459) == '150.604459'
202216
assert tester.PyOS_double_to_string_test(174.426353) == '174.426353'
203217
assert tester.PyOS_double_to_string_test(151.074362) == '151.074362'
204218
assert tester.PyOS_double_to_string_test(190.08) == '190.080000'
205219

206220
def test_PyOS_string_to_double(self):
207-
TestPyOS_String_To_Double = CPyExtType("TestPyOS_String_To_Double",
208-
'''
209-
static PyObject* testPyOS_Str_to_D(PyObject* self, PyObject *str) {
210-
char *endptr;
211-
const char *s = (char *) PyUnicode_AsUTF8(str);
212-
double ret = PyOS_string_to_double(s, &endptr, NULL);
213-
if (PyErr_Occurred()) {
214-
return NULL;
215-
}
216-
return PyFloat_FromDouble(ret);
217-
}
218-
''',
219-
tp_methods='{"PyOS_string_to_double_test", (PyCFunction)testPyOS_Str_to_D, METH_O, ""}',
220-
)
221+
TestPyOS_String_To_Double = CPyExtType(
222+
"TestPyOS_String_To_Double",
223+
'''
224+
static PyObject* testPyOS_Str_to_D(PyObject* self, PyObject *str) {
225+
char *endptr;
226+
const char *s = (char *) PyUnicode_AsUTF8(str);
227+
double ret = PyOS_string_to_double(s, &endptr, NULL);
228+
if (PyErr_Occurred()) {
229+
return NULL;
230+
}
231+
return PyFloat_FromDouble(ret);
232+
}
233+
''',
234+
tp_methods='{"PyOS_string_to_double_test", (PyCFunction)testPyOS_Str_to_D, METH_O, ""}',
235+
)
221236
tester = TestPyOS_String_To_Double()
222237
assert tester.PyOS_string_to_double_test('5') == float(5)
223238
assert tester.PyOS_string_to_double_test('150.604459') == float(150.604459)
239+
240+
241+
class TestNativeFloatSubclass:
242+
def test_create(self):
243+
f = NativeFloatSubclass(1.0)
244+
assert is_native_object(f)
245+
246+
class ManagedSubclass(NativeFloatSubclass):
247+
pass
248+
249+
f = ManagedSubclass(1.0)
250+
assert is_native_object(f)
251+
252+
def test_methods(self):
253+
f = NativeFloatSubclass(1.1)
254+
zero = NativeFloatSubclass(0.0)
255+
nan = NativeFloatSubclass('nan')
256+
257+
assert bool(f)
258+
assert not bool(zero)
259+
260+
assert f == 1.1
261+
assert nan != nan
262+
assert f != zero
263+
assert +f == 1.1
264+
assert -f == -1.1
265+
assert f > 0
266+
assert f < 2
267+
assert f >= 1.1
268+
assert f <= 1.1
269+
assert str(f) == '1.1'
270+
assert repr(f) == '1.1'
271+
assert int(f) == 1
272+
assert format(f, 'f') == '1.100000'
273+
assert abs(NativeFloatSubclass(-2.1)) == 2.1
274+
assert round(f) == 1.0
275+
assert f + 1.0 == 2.1
276+
assert 1.0 + f == 2.1
277+
assert f * 2 == 2.2
278+
assert f - 1.6 == -0.5
279+
assert f // 2 == 0.0
280+
assert f % 2 == 1.1
281+
assert f / 2.0 == 0.55
282+
assert f ** 0 == 1.0
283+
assert divmod(f, 2) == (0.0, 1.1)
284+
assert hash(f) == hash(1.1)
285+
assert f.hex() == (1.1).hex()
286+
assert f.real == 1.1
287+
assert f.imag == 0.0
288+
assert f.conjugate() == 1.1
289+
assert not f.is_integer()
290+
assert f.as_integer_ratio() == (1.1).as_integer_ratio()
291+
assert f.__getnewargs__() == (1.1,)
292+
293+
def test_math(self):
294+
assert math.isnan(NativeFloatSubclass('nan'))
295+
assert math.isinf(NativeFloatSubclass('inf'))
296+
assert not math.isfinite(NativeFloatSubclass('inf'))
297+
f = NativeFloatSubclass(0.9)
298+
for fn in [math.ceil, math.floor, math.sqrt, math.exp, math.expm1, math.frexp, math.modf, math.sin, math.asin,
299+
math.cos, math.acos, math.tan, math.atan, math.log2, math.log10, math.log1p, math.fabs, math.trunc,
300+
math.degrees, math.radians, math.gamma, math.lgamma, math.sqrt]:
301+
assert fn(f) == fn(0.9)
302+
303+
assert math.log(f, 10) == math.log(0.9, 10)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -826,7 +826,7 @@ public PTuple doDouble(double a, double b) {
826826
throw raise(PythonErrorType.ZeroDivisionError, ErrorMessages.DIVISION_BY_ZERO);
827827
}
828828
double q = Math.floor(a / b);
829-
return factory().createTuple(new Object[]{q, FloatBuiltins.ModNode.op(a, b)});
829+
return factory().createTuple(new Object[]{q, FloatBuiltins.ModNode.mod(a, b)});
830830
}
831831

832832
@Specialization

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/ByteArrayBuiltins.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ public PNone doInit(@SuppressWarnings("unused") PByteArray self, Object source,
182182

183183
@Specialization(guards = "!isBytes(self)")
184184
public PNone doInit(Object self, @SuppressWarnings("unused") Object source, @SuppressWarnings("unused") Object encoding, @SuppressWarnings("unused") Object errors) {
185-
throw raise(TypeError, ErrorMessages.DESCRIPTOR_REQUIRES_OBJ, T___INIT__, "bytearray", self);
185+
throw raise(TypeError, ErrorMessages.DESCRIPTOR_S_REQUIRES_S_OBJ_RECEIVED_P, T___INIT__, "bytearray", self);
186186
}
187187
}
188188

@@ -534,7 +534,7 @@ protected PNone doGeneric(VirtualFrame frame, PByteArray self, Object key,
534534
@SuppressWarnings("unused")
535535
@Fallback
536536
protected Object doGeneric(Object self, Object idx) {
537-
throw raise(TypeError, ErrorMessages.DESCRIPTOR_REQUIRES_OBJ, "__delitem__", "bytearray", idx);
537+
throw raise(TypeError, ErrorMessages.DESCRIPTOR_S_REQUIRES_S_OBJ_RECEIVED_P, "__delitem__", "bytearray", idx);
538538
}
539539
}
540540

@@ -841,7 +841,7 @@ static Object cmp(VirtualFrame frame, Object self, Object other,
841841
Object error(VirtualFrame frame, Object self, Object other,
842842
@Bind("this") Node inliningTarget,
843843
@Cached PyByteArrayCheckNode check) {
844-
throw raise(TypeError, ErrorMessages.DESCRIPTOR_REQUIRES_OBJ, J___EQ__, J_BYTEARRAY, self);
844+
throw raise(TypeError, ErrorMessages.DESCRIPTOR_S_REQUIRES_S_OBJ_RECEIVED_P, J___EQ__, J_BYTEARRAY, self);
845845
}
846846
}
847847

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesBuiltins.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,7 @@ static Object cmp(Object self, Object other,
587587
Object error(Object self, Object other,
588588
@Bind("this") Node inliningTarget,
589589
@Shared @Cached PyBytesCheckNode check) {
590-
throw raise(TypeError, ErrorMessages.DESCRIPTOR_REQUIRES_OBJ, J___EQ__, J_BYTES, self);
590+
throw raise(TypeError, ErrorMessages.DESCRIPTOR_S_REQUIRES_S_OBJ_RECEIVED_P, J___EQ__, J_BYTES, self);
591591
}
592592
}
593593

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cell/CellBuiltins.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ public Object eq(Object self, Object other) {
118118
if (self instanceof PCell) {
119119
return PNotImplemented.NOT_IMPLEMENTED;
120120
}
121-
throw raise(TypeError, ErrorMessages.DESCRIPTOR_REQUIRES_OBJ, T___EQ__, "cell", self);
121+
throw raise(TypeError, ErrorMessages.DESCRIPTOR_S_REQUIRES_S_OBJ_RECEIVED_P, T___EQ__, "cell", self);
122122
}
123123
}
124124

@@ -146,7 +146,7 @@ public Object eq(Object self, Object other) {
146146
if (self instanceof PCell) {
147147
return PNotImplemented.NOT_IMPLEMENTED;
148148
}
149-
throw raise(TypeError, ErrorMessages.DESCRIPTOR_REQUIRES_OBJ, T___NE__, "cell", self);
149+
throw raise(TypeError, ErrorMessages.DESCRIPTOR_S_REQUIRES_S_OBJ_RECEIVED_P, T___NE__, "cell", self);
150150
}
151151
}
152152

@@ -174,7 +174,7 @@ public Object notImplemented(Object self, Object other) {
174174
if (self instanceof PCell) {
175175
return PNotImplemented.NOT_IMPLEMENTED;
176176
}
177-
throw raise(TypeError, ErrorMessages.DESCRIPTOR_REQUIRES_OBJ, T___LT__, "cell", self);
177+
throw raise(TypeError, ErrorMessages.DESCRIPTOR_S_REQUIRES_S_OBJ_RECEIVED_P, T___LT__, "cell", self);
178178
}
179179
}
180180

@@ -202,7 +202,7 @@ public Object notImplemented(Object self, Object other) {
202202
if (self instanceof PCell) {
203203
return PNotImplemented.NOT_IMPLEMENTED;
204204
}
205-
throw raise(TypeError, ErrorMessages.DESCRIPTOR_REQUIRES_OBJ, T___LE__, "cell", self);
205+
throw raise(TypeError, ErrorMessages.DESCRIPTOR_S_REQUIRES_S_OBJ_RECEIVED_P, T___LE__, "cell", self);
206206
}
207207
}
208208

@@ -230,7 +230,7 @@ public Object notImplemented(Object self, Object other) {
230230
if (self instanceof PCell) {
231231
return PNotImplemented.NOT_IMPLEMENTED;
232232
}
233-
throw raise(TypeError, ErrorMessages.DESCRIPTOR_REQUIRES_OBJ, T___GT__, "cell", self);
233+
throw raise(TypeError, ErrorMessages.DESCRIPTOR_S_REQUIRES_S_OBJ_RECEIVED_P, T___GT__, "cell", self);
234234
}
235235
}
236236

@@ -258,7 +258,7 @@ public Object notImplemented(Object self, Object other) {
258258
if (self instanceof PCell) {
259259
return PNotImplemented.NOT_IMPLEMENTED;
260260
}
261-
throw raise(TypeError, ErrorMessages.DESCRIPTOR_REQUIRES_OBJ, T___GE__, "cell", self);
261+
throw raise(TypeError, ErrorMessages.DESCRIPTOR_S_REQUIRES_S_OBJ_RECEIVED_P, T___GE__, "cell", self);
262262
}
263263
}
264264

@@ -286,7 +286,7 @@ public Object eq(Object self) {
286286
if (self instanceof PCell) {
287287
return PNotImplemented.NOT_IMPLEMENTED;
288288
}
289-
throw raise(TypeError, ErrorMessages.DESCRIPTOR_REQUIRES_OBJ, "__repr__", "cell", self);
289+
throw raise(TypeError, ErrorMessages.DESCRIPTOR_S_REQUIRES_S_OBJ_RECEIVED_P, "__repr__", "cell", self);
290290
}
291291
}
292292

0 commit comments

Comments
 (0)