mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Compare commits
6 Commits
2024-12-30
...
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
|
||||
|
||||
from test import support
|
||||
from test.support import import_helper
|
||||
from test.support.testcase import FloatsAreIdenticalMixin
|
||||
from test.test_grammar import (VALID_UNDERSCORE_LITERALS,
|
||||
INVALID_UNDERSCORE_LITERALS)
|
||||
from math import isinf, isnan, copysign, ldexp
|
||||
@@ -19,7 +19,6 @@ try:
|
||||
except ImportError:
|
||||
_testcapi = None
|
||||
|
||||
HAVE_IEEE_754 = float.__getformat__("double").startswith("IEEE")
|
||||
INF = float("inf")
|
||||
NAN = float("nan")
|
||||
|
||||
@@ -742,8 +741,13 @@ class FormatTestCase(unittest.TestCase):
|
||||
|
||||
lhs, rhs = map(str.strip, line.split('->'))
|
||||
fmt, arg = lhs.split()
|
||||
self.assertEqual(fmt % float(arg), rhs)
|
||||
self.assertEqual(fmt % -float(arg), '-' + rhs)
|
||||
f = float(arg)
|
||||
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):
|
||||
self.assertEqual(format(123.456, '.4'), '123.5')
|
||||
@@ -833,7 +837,7 @@ class ReprTestCase(unittest.TestCase):
|
||||
self.assertEqual(repr(float(negs)), str(float(negs)))
|
||||
|
||||
@support.requires_IEEE_754
|
||||
class RoundTestCase(unittest.TestCase):
|
||||
class RoundTestCase(unittest.TestCase, FloatsAreIdenticalMixin):
|
||||
|
||||
def test_inf_nan(self):
|
||||
self.assertRaises(OverflowError, round, INF)
|
||||
@@ -863,10 +867,10 @@ class RoundTestCase(unittest.TestCase):
|
||||
|
||||
def test_small_n(self):
|
||||
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.assertEqual(round(-123.456, n), -0.0)
|
||||
self.assertEqual(round(1e300, n), 0.0)
|
||||
self.assertEqual(round(1e-320, n), 0.0)
|
||||
self.assertFloatsAreIdentical(round(123.456, n), 0.0)
|
||||
self.assertFloatsAreIdentical(round(-123.456, n), -0.0)
|
||||
self.assertFloatsAreIdentical(round(1e300, n), 0.0)
|
||||
self.assertFloatsAreIdentical(round(1e-320, n), 0.0)
|
||||
|
||||
def test_overflow(self):
|
||||
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)
|
||||
|
||||
@unittest.skipUnless(getattr(sys, 'float_repr_style', '') == 'short',
|
||||
"applies only when using short float repr style")
|
||||
def test_nan_signs(self):
|
||||
# When using the dtoa.c code, the sign of float('nan') should
|
||||
# be predictable.
|
||||
# The sign of float('nan') should be predictable.
|
||||
self.assertEqual(copysign(1.0, float('nan')), 1.0)
|
||||
self.assertEqual(copysign(1.0, float('-nan')), -1.0)
|
||||
|
||||
|
||||
fromHex = float.fromhex
|
||||
toHex = float.hex
|
||||
class HexFloatTestCase(unittest.TestCase):
|
||||
class HexFloatTestCase(FloatsAreIdenticalMixin, unittest.TestCase):
|
||||
MAX = fromHex('0x.fffffffffffff8p+1024') # max normal
|
||||
MIN = fromHex('0x1p-1022') # min normal
|
||||
TINY = fromHex('0x0.0000000000001p-1022') # min subnormal
|
||||
EPS = fromHex('0x0.0000000000001p0') # diff between 1.0 and next float up
|
||||
|
||||
def identical(self, x, y):
|
||||
# check that floats x and y are identical, or that both
|
||||
# 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))
|
||||
self.assertFloatsAreIdentical(x, y)
|
||||
|
||||
def test_ends(self):
|
||||
self.identical(self.MIN, ldexp(1.0, -1022))
|
||||
@@ -1517,69 +1511,5 @@ class HexFloatTestCase(unittest.TestCase):
|
||||
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__':
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user