forked from Rust-related/RustPython
Compare commits
6 Commits
dev
...
update_tes
| Author | SHA1 | Date | |
|---|---|---|---|
| 68c0eb6ed1 | |||
| 5c35ef9db0 | |||
| 308b95ec13 | |||
| 5f77ce5b4f | |||
| 4da57d42de | |||
| 2777588bb4 |
23
.github/workflows/ai-review.yml
vendored
Normal file
23
.github/workflows/ai-review.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
name: PR Review
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
review:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: AI Code Review
|
||||||
|
uses: gitea-actions/ai-reviewer@v0.6
|
||||||
|
with:
|
||||||
|
access-token: ${{ secrets.ACCESS_TOKEN }}
|
||||||
|
full-context-model: "gpt-4o"
|
||||||
|
full-context-api-key: ${{ secrets.OPENAI_API_KEY }}
|
||||||
|
single-chunk-model: "claude-3-5-sonnet"
|
||||||
|
single-chunk-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||||
|
exclude-files: "*.md,*.yaml"
|
||||||
65
Lib/test/support/testcase.py
vendored
Normal file
65
Lib/test/support/testcase.py
vendored
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
from math import copysign, isnan
|
||||||
|
|
||||||
|
|
||||||
|
class ExceptionIsLikeMixin:
|
||||||
|
def assertExceptionIsLike(self, exc, template):
|
||||||
|
"""
|
||||||
|
Passes when the provided `exc` matches the structure of `template`.
|
||||||
|
Individual exceptions don't have to be the same objects or even pass
|
||||||
|
an equality test: they only need to be the same type and contain equal
|
||||||
|
`exc_obj.args`.
|
||||||
|
"""
|
||||||
|
if exc is None and template is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
if template is None:
|
||||||
|
self.fail(f"unexpected exception: {exc}")
|
||||||
|
|
||||||
|
if exc is None:
|
||||||
|
self.fail(f"expected an exception like {template!r}, got None")
|
||||||
|
|
||||||
|
if not isinstance(exc, ExceptionGroup):
|
||||||
|
self.assertEqual(exc.__class__, template.__class__)
|
||||||
|
self.assertEqual(exc.args[0], template.args[0])
|
||||||
|
else:
|
||||||
|
self.assertEqual(exc.message, template.message)
|
||||||
|
self.assertEqual(len(exc.exceptions), len(template.exceptions))
|
||||||
|
for e, t in zip(exc.exceptions, template.exceptions):
|
||||||
|
self.assertExceptionIsLike(e, t)
|
||||||
|
|
||||||
|
|
||||||
|
class FloatsAreIdenticalMixin:
|
||||||
|
def assertFloatsAreIdentical(self, x, y):
|
||||||
|
"""Fail unless floats x and y are identical, in the sense that:
|
||||||
|
(1) both x and y are nans, or
|
||||||
|
(2) both x and y are infinities, with the same sign, or
|
||||||
|
(3) both x and y are zeros, with the same sign, or
|
||||||
|
(4) x and y are both finite and nonzero, and x == y
|
||||||
|
|
||||||
|
"""
|
||||||
|
msg = 'floats {!r} and {!r} are not identical'
|
||||||
|
|
||||||
|
if isnan(x) or isnan(y):
|
||||||
|
if isnan(x) and isnan(y):
|
||||||
|
return
|
||||||
|
elif x == y:
|
||||||
|
if x != 0.0:
|
||||||
|
return
|
||||||
|
# both zero; check that signs match
|
||||||
|
elif copysign(1.0, x) == copysign(1.0, y):
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
msg += ': zeros have different signs'
|
||||||
|
self.fail(msg.format(x, y))
|
||||||
|
|
||||||
|
|
||||||
|
class ComplexesAreIdenticalMixin(FloatsAreIdenticalMixin):
|
||||||
|
def assertComplexesAreIdentical(self, x, y):
|
||||||
|
"""Fail unless complex numbers x and y have equal values and signs.
|
||||||
|
|
||||||
|
In particular, if x and y both have real (or imaginary) part
|
||||||
|
zero, but the zeros have different signs, this test will fail.
|
||||||
|
|
||||||
|
"""
|
||||||
|
self.assertFloatsAreIdentical(x.real, y.real)
|
||||||
|
self.assertFloatsAreIdentical(x.imag, y.imag)
|
||||||
102
Lib/test/test_float.py
vendored
102
Lib/test/test_float.py
vendored
@@ -8,7 +8,7 @@ import time
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from test import support
|
from test import support
|
||||||
from test.support import import_helper
|
from test.support.testcase import FloatsAreIdenticalMixin
|
||||||
from test.test_grammar import (VALID_UNDERSCORE_LITERALS,
|
from test.test_grammar import (VALID_UNDERSCORE_LITERALS,
|
||||||
INVALID_UNDERSCORE_LITERALS)
|
INVALID_UNDERSCORE_LITERALS)
|
||||||
from math import isinf, isnan, copysign, ldexp
|
from math import isinf, isnan, copysign, ldexp
|
||||||
@@ -19,7 +19,6 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
_testcapi = None
|
_testcapi = None
|
||||||
|
|
||||||
HAVE_IEEE_754 = float.__getformat__("double").startswith("IEEE")
|
|
||||||
INF = float("inf")
|
INF = float("inf")
|
||||||
NAN = float("nan")
|
NAN = float("nan")
|
||||||
|
|
||||||
@@ -742,8 +741,13 @@ class FormatTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
lhs, rhs = map(str.strip, line.split('->'))
|
lhs, rhs = map(str.strip, line.split('->'))
|
||||||
fmt, arg = lhs.split()
|
fmt, arg = lhs.split()
|
||||||
self.assertEqual(fmt % float(arg), rhs)
|
f = float(arg)
|
||||||
self.assertEqual(fmt % -float(arg), '-' + rhs)
|
self.assertEqual(fmt % f, rhs)
|
||||||
|
self.assertEqual(fmt % -f, '-' + rhs)
|
||||||
|
if fmt != '%r':
|
||||||
|
fmt2 = fmt[1:]
|
||||||
|
self.assertEqual(format(f, fmt2), rhs)
|
||||||
|
self.assertEqual(format(-f, fmt2), '-' + rhs)
|
||||||
|
|
||||||
def test_issue5864(self):
|
def test_issue5864(self):
|
||||||
self.assertEqual(format(123.456, '.4'), '123.5')
|
self.assertEqual(format(123.456, '.4'), '123.5')
|
||||||
@@ -833,7 +837,7 @@ class ReprTestCase(unittest.TestCase):
|
|||||||
self.assertEqual(repr(float(negs)), str(float(negs)))
|
self.assertEqual(repr(float(negs)), str(float(negs)))
|
||||||
|
|
||||||
@support.requires_IEEE_754
|
@support.requires_IEEE_754
|
||||||
class RoundTestCase(unittest.TestCase):
|
class RoundTestCase(unittest.TestCase, FloatsAreIdenticalMixin):
|
||||||
|
|
||||||
def test_inf_nan(self):
|
def test_inf_nan(self):
|
||||||
self.assertRaises(OverflowError, round, INF)
|
self.assertRaises(OverflowError, round, INF)
|
||||||
@@ -863,10 +867,10 @@ class RoundTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
def test_small_n(self):
|
def test_small_n(self):
|
||||||
for n in [-308, -309, -400, 1-2**31, -2**31, -2**31-1, -2**100]:
|
for n in [-308, -309, -400, 1-2**31, -2**31, -2**31-1, -2**100]:
|
||||||
self.assertEqual(round(123.456, n), 0.0)
|
self.assertFloatsAreIdentical(round(123.456, n), 0.0)
|
||||||
self.assertEqual(round(-123.456, n), -0.0)
|
self.assertFloatsAreIdentical(round(-123.456, n), -0.0)
|
||||||
self.assertEqual(round(1e300, n), 0.0)
|
self.assertFloatsAreIdentical(round(1e300, n), 0.0)
|
||||||
self.assertEqual(round(1e-320, n), 0.0)
|
self.assertFloatsAreIdentical(round(1e-320, n), 0.0)
|
||||||
|
|
||||||
def test_overflow(self):
|
def test_overflow(self):
|
||||||
self.assertRaises(OverflowError, round, 1.6e308, -308)
|
self.assertRaises(OverflowError, round, 1.6e308, -308)
|
||||||
@@ -1053,32 +1057,22 @@ class InfNanTest(unittest.TestCase):
|
|||||||
self.assertEqual(copysign(1.0, float('inf')), 1.0)
|
self.assertEqual(copysign(1.0, float('inf')), 1.0)
|
||||||
self.assertEqual(copysign(1.0, float('-inf')), -1.0)
|
self.assertEqual(copysign(1.0, float('-inf')), -1.0)
|
||||||
|
|
||||||
@unittest.skipUnless(getattr(sys, 'float_repr_style', '') == 'short',
|
|
||||||
"applies only when using short float repr style")
|
|
||||||
def test_nan_signs(self):
|
def test_nan_signs(self):
|
||||||
# When using the dtoa.c code, the sign of float('nan') should
|
# The sign of float('nan') should be predictable.
|
||||||
# be predictable.
|
|
||||||
self.assertEqual(copysign(1.0, float('nan')), 1.0)
|
self.assertEqual(copysign(1.0, float('nan')), 1.0)
|
||||||
self.assertEqual(copysign(1.0, float('-nan')), -1.0)
|
self.assertEqual(copysign(1.0, float('-nan')), -1.0)
|
||||||
|
|
||||||
|
|
||||||
fromHex = float.fromhex
|
fromHex = float.fromhex
|
||||||
toHex = float.hex
|
toHex = float.hex
|
||||||
class HexFloatTestCase(unittest.TestCase):
|
class HexFloatTestCase(FloatsAreIdenticalMixin, unittest.TestCase):
|
||||||
MAX = fromHex('0x.fffffffffffff8p+1024') # max normal
|
MAX = fromHex('0x.fffffffffffff8p+1024') # max normal
|
||||||
MIN = fromHex('0x1p-1022') # min normal
|
MIN = fromHex('0x1p-1022') # min normal
|
||||||
TINY = fromHex('0x0.0000000000001p-1022') # min subnormal
|
TINY = fromHex('0x0.0000000000001p-1022') # min subnormal
|
||||||
EPS = fromHex('0x0.0000000000001p0') # diff between 1.0 and next float up
|
EPS = fromHex('0x0.0000000000001p0') # diff between 1.0 and next float up
|
||||||
|
|
||||||
def identical(self, x, y):
|
def identical(self, x, y):
|
||||||
# check that floats x and y are identical, or that both
|
self.assertFloatsAreIdentical(x, y)
|
||||||
# are NaNs
|
|
||||||
if isnan(x) or isnan(y):
|
|
||||||
if isnan(x) == isnan(y):
|
|
||||||
return
|
|
||||||
elif x == y and (x != 0.0 or copysign(1.0, x) == copysign(1.0, y)):
|
|
||||||
return
|
|
||||||
self.fail('%r not identical to %r' % (x, y))
|
|
||||||
|
|
||||||
def test_ends(self):
|
def test_ends(self):
|
||||||
self.identical(self.MIN, ldexp(1.0, -1022))
|
self.identical(self.MIN, ldexp(1.0, -1022))
|
||||||
@@ -1517,69 +1511,5 @@ class HexFloatTestCase(unittest.TestCase):
|
|||||||
self.assertEqual(getattr(f, 'foo', 'none'), 'bar')
|
self.assertEqual(getattr(f, 'foo', 'none'), 'bar')
|
||||||
|
|
||||||
|
|
||||||
# Test PyFloat_Pack2(), PyFloat_Pack4() and PyFloat_Pack8()
|
|
||||||
# Test PyFloat_Unpack2(), PyFloat_Unpack4() and PyFloat_Unpack8()
|
|
||||||
BIG_ENDIAN = 0
|
|
||||||
LITTLE_ENDIAN = 1
|
|
||||||
EPSILON = {
|
|
||||||
2: 2.0 ** -11, # binary16
|
|
||||||
4: 2.0 ** -24, # binary32
|
|
||||||
8: 2.0 ** -53, # binary64
|
|
||||||
}
|
|
||||||
|
|
||||||
@unittest.skipIf(_testcapi is None, 'needs _testcapi')
|
|
||||||
class PackTests(unittest.TestCase):
|
|
||||||
def test_pack(self):
|
|
||||||
self.assertEqual(_testcapi.float_pack(2, 1.5, BIG_ENDIAN),
|
|
||||||
b'>\x00')
|
|
||||||
self.assertEqual(_testcapi.float_pack(4, 1.5, BIG_ENDIAN),
|
|
||||||
b'?\xc0\x00\x00')
|
|
||||||
self.assertEqual(_testcapi.float_pack(8, 1.5, BIG_ENDIAN),
|
|
||||||
b'?\xf8\x00\x00\x00\x00\x00\x00')
|
|
||||||
self.assertEqual(_testcapi.float_pack(2, 1.5, LITTLE_ENDIAN),
|
|
||||||
b'\x00>')
|
|
||||||
self.assertEqual(_testcapi.float_pack(4, 1.5, LITTLE_ENDIAN),
|
|
||||||
b'\x00\x00\xc0?')
|
|
||||||
self.assertEqual(_testcapi.float_pack(8, 1.5, LITTLE_ENDIAN),
|
|
||||||
b'\x00\x00\x00\x00\x00\x00\xf8?')
|
|
||||||
|
|
||||||
def test_unpack(self):
|
|
||||||
self.assertEqual(_testcapi.float_unpack(b'>\x00', BIG_ENDIAN),
|
|
||||||
1.5)
|
|
||||||
self.assertEqual(_testcapi.float_unpack(b'?\xc0\x00\x00', BIG_ENDIAN),
|
|
||||||
1.5)
|
|
||||||
self.assertEqual(_testcapi.float_unpack(b'?\xf8\x00\x00\x00\x00\x00\x00', BIG_ENDIAN),
|
|
||||||
1.5)
|
|
||||||
self.assertEqual(_testcapi.float_unpack(b'\x00>', LITTLE_ENDIAN),
|
|
||||||
1.5)
|
|
||||||
self.assertEqual(_testcapi.float_unpack(b'\x00\x00\xc0?', LITTLE_ENDIAN),
|
|
||||||
1.5)
|
|
||||||
self.assertEqual(_testcapi.float_unpack(b'\x00\x00\x00\x00\x00\x00\xf8?', LITTLE_ENDIAN),
|
|
||||||
1.5)
|
|
||||||
|
|
||||||
def test_roundtrip(self):
|
|
||||||
large = 2.0 ** 100
|
|
||||||
values = [1.0, 1.5, large, 1.0/7, math.pi]
|
|
||||||
if HAVE_IEEE_754:
|
|
||||||
values.extend((INF, NAN))
|
|
||||||
for value in values:
|
|
||||||
for size in (2, 4, 8,):
|
|
||||||
if size == 2 and value == large:
|
|
||||||
# too large for 16-bit float
|
|
||||||
continue
|
|
||||||
rel_tol = EPSILON[size]
|
|
||||||
for endian in (BIG_ENDIAN, LITTLE_ENDIAN):
|
|
||||||
with self.subTest(value=value, size=size, endian=endian):
|
|
||||||
data = _testcapi.float_pack(size, value, endian)
|
|
||||||
value2 = _testcapi.float_unpack(data, endian)
|
|
||||||
if isnan(value):
|
|
||||||
self.assertTrue(isnan(value2), (value, value2))
|
|
||||||
elif size < 8:
|
|
||||||
self.assertTrue(math.isclose(value2, value, rel_tol=rel_tol),
|
|
||||||
(value, value2))
|
|
||||||
else:
|
|
||||||
self.assertEqual(value2, value)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
Reference in New Issue
Block a user