Skip to content

Commit fef32a1

Browse files
[3.12] gh-111495: Add tests for PyFloat C API (GH-111624) (GH-111752)
(cherry picked from commit b452202) Co-authored-by: Sergey B Kirpichev <[email protected]>
1 parent 237b269 commit fef32a1

File tree

2 files changed

+191
-0
lines changed

2 files changed

+191
-0
lines changed

Lib/test/test_capi/test_float.py

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import math
2+
import sys
3+
import unittest
4+
import warnings
5+
6+
from test.test_capi.test_getargs import (Float, FloatSubclass, FloatSubclass2,
7+
BadIndex2, BadFloat2, Index, BadIndex,
8+
BadFloat)
9+
from test.support import import_helper
10+
11+
_testcapi = import_helper.import_module('_testcapi')
12+
13+
NULL = None
14+
15+
16+
class CAPIFloatTest(unittest.TestCase):
17+
def test_check(self):
18+
# Test PyFloat_Check()
19+
check = _testcapi.float_check
20+
21+
self.assertTrue(check(4.25))
22+
self.assertTrue(check(FloatSubclass(4.25)))
23+
self.assertFalse(check(Float()))
24+
self.assertFalse(check(3))
25+
self.assertFalse(check(object()))
26+
27+
# CRASHES check(NULL)
28+
29+
def test_checkexact(self):
30+
# Test PyFloat_CheckExact()
31+
checkexact = _testcapi.float_checkexact
32+
33+
self.assertTrue(checkexact(4.25))
34+
self.assertFalse(checkexact(FloatSubclass(4.25)))
35+
self.assertFalse(checkexact(Float()))
36+
self.assertFalse(checkexact(3))
37+
self.assertFalse(checkexact(object()))
38+
39+
# CRASHES checkexact(NULL)
40+
41+
def test_fromstring(self):
42+
# Test PyFloat_FromString()
43+
fromstring = _testcapi.float_fromstring
44+
45+
self.assertEqual(fromstring("4.25"), 4.25)
46+
self.assertEqual(fromstring(b"4.25"), 4.25)
47+
self.assertRaises(ValueError, fromstring, "4.25\0")
48+
self.assertRaises(ValueError, fromstring, b"4.25\0")
49+
50+
self.assertEqual(fromstring(bytearray(b"4.25")), 4.25)
51+
52+
self.assertEqual(fromstring(memoryview(b"4.25")), 4.25)
53+
self.assertEqual(fromstring(memoryview(b"4.255")[:-1]), 4.25)
54+
self.assertRaises(TypeError, fromstring, memoryview(b"4.25")[::2])
55+
56+
self.assertRaises(TypeError, fromstring, 4.25)
57+
58+
# CRASHES fromstring(NULL)
59+
60+
def test_fromdouble(self):
61+
# Test PyFloat_FromDouble()
62+
fromdouble = _testcapi.float_fromdouble
63+
64+
self.assertEqual(fromdouble(4.25), 4.25)
65+
66+
def test_asdouble(self):
67+
# Test PyFloat_AsDouble()
68+
asdouble = _testcapi.float_asdouble
69+
70+
class BadFloat3:
71+
def __float__(self):
72+
raise RuntimeError
73+
74+
self.assertEqual(asdouble(4.25), 4.25)
75+
self.assertEqual(asdouble(-1.0), -1.0)
76+
self.assertEqual(asdouble(42), 42.0)
77+
self.assertEqual(asdouble(-1), -1.0)
78+
self.assertEqual(asdouble(2**1000), float(2**1000))
79+
80+
self.assertEqual(asdouble(FloatSubclass(4.25)), 4.25)
81+
self.assertEqual(asdouble(FloatSubclass2(4.25)), 4.25)
82+
self.assertEqual(asdouble(Index()), 99.)
83+
84+
self.assertRaises(TypeError, asdouble, BadIndex())
85+
self.assertRaises(TypeError, asdouble, BadFloat())
86+
self.assertRaises(RuntimeError, asdouble, BadFloat3())
87+
with self.assertWarns(DeprecationWarning):
88+
self.assertEqual(asdouble(BadIndex2()), 1.)
89+
with self.assertWarns(DeprecationWarning):
90+
self.assertEqual(asdouble(BadFloat2()), 4.25)
91+
with warnings.catch_warnings():
92+
warnings.simplefilter("error", DeprecationWarning)
93+
self.assertRaises(DeprecationWarning, asdouble, BadFloat2())
94+
self.assertRaises(TypeError, asdouble, object())
95+
self.assertRaises(TypeError, asdouble, NULL)
96+
97+
def test_getinfo(self):
98+
# Test PyFloat_GetInfo()
99+
getinfo = _testcapi.float_getinfo
100+
101+
self.assertEqual(getinfo(), sys.float_info)
102+
103+
def test_getmax(self):
104+
# Test PyFloat_GetMax()
105+
getmax = _testcapi.float_getmax
106+
107+
self.assertEqual(getmax(), sys.float_info.max)
108+
109+
def test_getmin(self):
110+
# Test PyFloat_GetMax()
111+
getmin = _testcapi.float_getmin
112+
113+
self.assertEqual(getmin(), sys.float_info.min)
114+
115+
116+
if __name__ == "__main__":
117+
unittest.main()

Modules/_testcapi/float.c

+74
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,75 @@
11
#define PY_SSIZE_T_CLEAN
22

33
#include "parts.h"
4+
#include "util.h"
45
#include "clinic/float.c.h"
56

67

8+
static PyObject *
9+
float_check(PyObject *Py_UNUSED(module), PyObject *obj)
10+
{
11+
NULLABLE(obj);
12+
return PyLong_FromLong(PyFloat_Check(obj));
13+
}
14+
15+
static PyObject *
16+
float_checkexact(PyObject *Py_UNUSED(module), PyObject *obj)
17+
{
18+
NULLABLE(obj);
19+
return PyLong_FromLong(PyFloat_CheckExact(obj));
20+
}
21+
22+
static PyObject *
23+
float_fromstring(PyObject *Py_UNUSED(module), PyObject *obj)
24+
{
25+
NULLABLE(obj);
26+
return PyFloat_FromString(obj);
27+
}
28+
29+
static PyObject *
30+
float_fromdouble(PyObject *Py_UNUSED(module), PyObject *obj)
31+
{
32+
double d;
33+
34+
if (!PyArg_Parse(obj, "d", &d)) {
35+
return NULL;
36+
}
37+
38+
return PyFloat_FromDouble(d);
39+
}
40+
41+
static PyObject *
42+
float_asdouble(PyObject *Py_UNUSED(module), PyObject *obj)
43+
{
44+
double d;
45+
46+
NULLABLE(obj);
47+
d = PyFloat_AsDouble(obj);
48+
if (d == -1. && PyErr_Occurred()) {
49+
return NULL;
50+
}
51+
52+
return PyFloat_FromDouble(d);
53+
}
54+
55+
static PyObject *
56+
float_getinfo(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(arg))
57+
{
58+
return PyFloat_GetInfo();
59+
}
60+
61+
static PyObject *
62+
float_getmax(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(arg))
63+
{
64+
return PyFloat_FromDouble(PyFloat_GetMax());
65+
}
66+
67+
static PyObject *
68+
float_getmin(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(arg))
69+
{
70+
return PyFloat_FromDouble(PyFloat_GetMin());
71+
}
72+
773
/*[clinic input]
874
module _testcapi
975
[clinic start generated code]*/
@@ -98,6 +164,14 @@ _testcapi_float_unpack_impl(PyObject *module, const char *data,
98164
}
99165

100166
static PyMethodDef test_methods[] = {
167+
{"float_check", float_check, METH_O},
168+
{"float_checkexact", float_checkexact, METH_O},
169+
{"float_fromstring", float_fromstring, METH_O},
170+
{"float_fromdouble", float_fromdouble, METH_O},
171+
{"float_asdouble", float_asdouble, METH_O},
172+
{"float_getinfo", float_getinfo, METH_NOARGS},
173+
{"float_getmax", float_getmax, METH_NOARGS},
174+
{"float_getmin", float_getmin, METH_NOARGS},
101175
_TESTCAPI_FLOAT_PACK_METHODDEF
102176
_TESTCAPI_FLOAT_UNPACK_METHODDEF
103177
{NULL},

0 commit comments

Comments
 (0)