Skip to content

Commit

Permalink
Merge branch '3.13' into backport-d2b9b6f-3.13
Browse files Browse the repository at this point in the history
  • Loading branch information
Yhg1s authored Sep 30, 2024
2 parents 04d18c8 + 62e54dd commit a0a19e8
Show file tree
Hide file tree
Showing 16 changed files with 145 additions and 122 deletions.
4 changes: 1 addition & 3 deletions Lib/test/pickletester.py
Original file line number Diff line number Diff line change
Expand Up @@ -2017,12 +2017,10 @@ def test_picklebuffer_error(self):
'PickleBuffer can only be pickled with protocol >= 5')

def test_non_continuous_buffer(self):
if self.pickler is pickle._Pickler:
self.skipTest('CRASHES (see gh-122306)')
for proto in protocols[5:]:
with self.subTest(proto=proto):
pb = pickle.PickleBuffer(memoryview(b"foobar")[::2])
with self.assertRaises(pickle.PicklingError):
with self.assertRaises((pickle.PicklingError, BufferError)):
self.dumps(pb, proto)

def test_buffer_callback_error(self):
Expand Down
40 changes: 40 additions & 0 deletions Lib/test/support/testcase.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
from math import copysign, isnan


class ExceptionIsLikeMixin:
def assertExceptionIsLike(self, exc, template):
"""
Expand All @@ -23,3 +26,40 @@ def assertExceptionIsLike(self, exc, template):
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)
27 changes: 12 additions & 15 deletions Lib/test/test_capi/test_getargs.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from test.support import import_helper
from test.support import script_helper
from test.support import warnings_helper
from test.support.testcase import FloatsAreIdenticalMixin
# Skip this test if the _testcapi module isn't available.
_testcapi = import_helper.import_module('_testcapi')
from _testcapi import getargs_keywords, getargs_keyword_only
Expand Down Expand Up @@ -436,11 +437,7 @@ def test_K(self):
self.assertEqual(VERY_LARGE & ULLONG_MAX, getargs_K(VERY_LARGE))


class Float_TestCase(unittest.TestCase):
def assertEqualWithSign(self, actual, expected):
self.assertEqual(actual, expected)
self.assertEqual(math.copysign(1, actual), math.copysign(1, expected))

class Float_TestCase(unittest.TestCase, FloatsAreIdenticalMixin):
def test_f(self):
from _testcapi import getargs_f
self.assertEqual(getargs_f(4.25), 4.25)
Expand All @@ -462,10 +459,10 @@ def test_f(self):
self.assertEqual(getargs_f(DBL_MAX), INF)
self.assertEqual(getargs_f(-DBL_MAX), -INF)
if FLT_MIN > DBL_MIN:
self.assertEqualWithSign(getargs_f(DBL_MIN), 0.0)
self.assertEqualWithSign(getargs_f(-DBL_MIN), -0.0)
self.assertEqualWithSign(getargs_f(0.0), 0.0)
self.assertEqualWithSign(getargs_f(-0.0), -0.0)
self.assertFloatsAreIdentical(getargs_f(DBL_MIN), 0.0)
self.assertFloatsAreIdentical(getargs_f(-DBL_MIN), -0.0)
self.assertFloatsAreIdentical(getargs_f(0.0), 0.0)
self.assertFloatsAreIdentical(getargs_f(-0.0), -0.0)
r = getargs_f(NAN)
self.assertNotEqual(r, r)

Expand Down Expand Up @@ -494,8 +491,8 @@ def test_d(self):
self.assertEqual(getargs_d(x), x)
self.assertRaises(OverflowError, getargs_d, 1<<DBL_MAX_EXP)
self.assertRaises(OverflowError, getargs_d, -1<<DBL_MAX_EXP)
self.assertEqualWithSign(getargs_d(0.0), 0.0)
self.assertEqualWithSign(getargs_d(-0.0), -0.0)
self.assertFloatsAreIdentical(getargs_d(0.0), 0.0)
self.assertFloatsAreIdentical(getargs_d(-0.0), -0.0)
r = getargs_d(NAN)
self.assertNotEqual(r, r)

Expand All @@ -519,10 +516,10 @@ def test_D(self):
self.assertEqual(getargs_D(c), c)
c = complex(1.0, x)
self.assertEqual(getargs_D(c), c)
self.assertEqualWithSign(getargs_D(complex(0.0, 1.0)).real, 0.0)
self.assertEqualWithSign(getargs_D(complex(-0.0, 1.0)).real, -0.0)
self.assertEqualWithSign(getargs_D(complex(1.0, 0.0)).imag, 0.0)
self.assertEqualWithSign(getargs_D(complex(1.0, -0.0)).imag, -0.0)
self.assertFloatsAreIdentical(getargs_D(complex(0.0, 1.0)).real, 0.0)
self.assertFloatsAreIdentical(getargs_D(complex(-0.0, 1.0)).real, -0.0)
self.assertFloatsAreIdentical(getargs_D(complex(1.0, 0.0)).imag, 0.0)
self.assertFloatsAreIdentical(getargs_D(complex(1.0, -0.0)).imag, -0.0)


class Paradox:
Expand Down
42 changes: 5 additions & 37 deletions Lib/test/test_cmath.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from test.support import requires_IEEE_754, cpython_only, import_helper
from test.support.testcase import ComplexesAreIdenticalMixin
from test.test_math import parse_testfile, test_file
import test.test_math as test_math
import unittest
Expand Down Expand Up @@ -49,7 +50,7 @@
(INF, NAN)
]]

class CMathTests(unittest.TestCase):
class CMathTests(ComplexesAreIdenticalMixin, unittest.TestCase):
# list of all functions in cmath
test_functions = [getattr(cmath, fname) for fname in [
'acos', 'acosh', 'asin', 'asinh', 'atan', 'atanh',
Expand All @@ -65,39 +66,6 @@ def setUp(self):
def tearDown(self):
self.test_values.close()

def assertFloatIdentical(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 math.isnan(x) or math.isnan(y):
if math.isnan(x) and math.isnan(y):
return
elif x == y:
if x != 0.0:
return
# both zero; check that signs match
elif math.copysign(1.0, x) == math.copysign(1.0, y):
return
else:
msg += ': zeros have different signs'
self.fail(msg.format(x, y))

def assertComplexIdentical(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.assertFloatIdentical(x.real, y.real)
self.assertFloatIdentical(x.imag, y.imag)

def rAssertAlmostEqual(self, a, b, rel_err = 2e-15, abs_err = 5e-323,
msg=None):
"""Fail if the two floating-point numbers are not almost equal.
Expand Down Expand Up @@ -555,7 +523,7 @@ def test_isinf(self):
@requires_IEEE_754
def testTanhSign(self):
for z in complex_zeros:
self.assertComplexIdentical(cmath.tanh(z), z)
self.assertComplexesAreIdentical(cmath.tanh(z), z)

# The algorithm used for atan and atanh makes use of the system
# log1p function; If that system function doesn't respect the sign
Expand All @@ -564,12 +532,12 @@ def testTanhSign(self):
@requires_IEEE_754
def testAtanSign(self):
for z in complex_zeros:
self.assertComplexIdentical(cmath.atan(z), z)
self.assertComplexesAreIdentical(cmath.atan(z), z)

@requires_IEEE_754
def testAtanhSign(self):
for z in complex_zeros:
self.assertComplexIdentical(cmath.atanh(z), z)
self.assertComplexesAreIdentical(cmath.atanh(z), z)


class IsCloseTests(test_math.IsCloseTests):
Expand Down
29 changes: 3 additions & 26 deletions Lib/test/test_complex.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import unittest
import sys
from test import support
from test.support.testcase import ComplexesAreIdenticalMixin
from test.test_grammar import (VALID_UNDERSCORE_LITERALS,
INVALID_UNDERSCORE_LITERALS)

Expand Down Expand Up @@ -42,7 +43,7 @@ def __init__(self, value):
def __complex__(self):
return self.value

class ComplexTest(unittest.TestCase):
class ComplexTest(ComplexesAreIdenticalMixin, unittest.TestCase):

def assertAlmostEqual(self, a, b):
if isinstance(a, complex):
Expand Down Expand Up @@ -71,29 +72,6 @@ def assertCloseAbs(self, x, y, eps=1e-9):
# check that relative difference < eps
self.assertTrue(abs((x-y)/y) < eps)

def assertFloatsAreIdentical(self, x, y):
"""assert that 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))

def assertClose(self, x, y, eps=1e-9):
"""Return true iff complexes x and y "are close"."""
self.assertCloseAbs(x.real, y.real, eps)
Expand Down Expand Up @@ -731,8 +709,7 @@ def test_repr_roundtrip(self):
for y in vals:
z = complex(x, y)
roundtrip = complex(repr(z))
self.assertFloatsAreIdentical(z.real, roundtrip.real)
self.assertFloatsAreIdentical(z.imag, roundtrip.imag)
self.assertComplexesAreIdentical(z, roundtrip)

# if we predefine some constants, then eval(repr(z)) should
# also work, except that it might change the sign of zeros
Expand Down
12 changes: 3 additions & 9 deletions Lib/test/test_float.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import unittest

from test import support
from test.support.testcase import FloatsAreIdenticalMixin
from test.test_grammar import (VALID_UNDERSCORE_LITERALS,
INVALID_UNDERSCORE_LITERALS)
from math import isinf, isnan, copysign, ldexp
Expand Down Expand Up @@ -1053,21 +1054,14 @@ def test_nan_signs(self):

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))
Expand Down
27 changes: 25 additions & 2 deletions Lib/test/test_memoryview.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
from test.support import import_helper


class MyObject:
pass


class AbstractMemoryTests:
source_bytes = b"abcdef"

Expand Down Expand Up @@ -228,8 +232,6 @@ def __init__(self, base):
self.m = memoryview(base)
class MySource(tp):
pass
class MyObject:
pass

# Create a reference cycle through a memoryview object.
# This exercises mbuf_clear().
Expand Down Expand Up @@ -656,5 +658,26 @@ def __bool__(self):
m[0] = MyBool()
self.assertEqual(ba[:8], b'\0'*8)

def test_buffer_reference_loop(self):
m = memoryview(b'abc').__buffer__(0)
o = MyObject()
o.m = m
o.o = o
wr = weakref.ref(o)
del m, o
gc.collect()
self.assertIsNone(wr())

def test_picklebuffer_reference_loop(self):
pb = pickle.PickleBuffer(memoryview(b'abc'))
o = MyObject()
o.pb = pb
o.o = o
wr = weakref.ref(o)
del pb, o
gc.collect()
self.assertIsNone(wr())


if __name__ == "__main__":
unittest.main()
4 changes: 3 additions & 1 deletion Lib/test/test_posix.py
Original file line number Diff line number Diff line change
Expand Up @@ -411,8 +411,10 @@ def test_posix_fallocate(self):
# issue33655: Also ignore EINVAL on *BSD since ZFS is also
# often used there.
if inst.errno == errno.EINVAL and sys.platform.startswith(
('sunos', 'freebsd', 'netbsd', 'openbsd', 'gnukfreebsd')):
('sunos', 'freebsd', 'openbsd', 'gnukfreebsd')):
raise unittest.SkipTest("test may fail on ZFS filesystems")
elif inst.errno == errno.EOPNOTSUPP and sys.platform.startswith("netbsd"):
raise unittest.SkipTest("test may fail on FFS filesystems")
else:
raise
finally:
Expand Down
17 changes: 17 additions & 0 deletions Lib/test/test_type_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -950,6 +950,7 @@ class C[T](Base, a=1, b=2, **kwargs):
T, = C.__type_params__
self.assertEqual(T.__name__, "T")
self.assertEqual(C.kwargs, {"a": 1, "b": 2, "c": 3})
self.assertEqual(C.__bases__, (Base, Generic))

bases = (Base,)
class C2[T](*bases, **kwargs):
Expand All @@ -958,6 +959,22 @@ class C2[T](*bases, **kwargs):
T, = C2.__type_params__
self.assertEqual(T.__name__, "T")
self.assertEqual(C2.kwargs, {"c": 3})
self.assertEqual(C2.__bases__, (Base, Generic))

def test_starargs_base(self):
class C1[T](*()): pass

T, = C1.__type_params__
self.assertEqual(T.__name__, "T")
self.assertEqual(C1.__bases__, (Generic,))

class Base: pass
bases = [Base]
class C2[T](*bases): pass

T, = C2.__type_params__
self.assertEqual(T.__name__, "T")
self.assertEqual(C2.__bases__, (Base, Generic))


class TypeParamsTraditionalTypeVarsTest(unittest.TestCase):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Fix possible crash in the garbage collector when it tries to break a
reference loop containing a :class:`memoryview` object. Now a
:class:`!memoryview` object can only be cleared if there are no buffers that
refer it.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add ``"_wmi"`` to :data:`sys.stdlib_module_names`. Patch by Victor Stinner.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Ensure that ``Tools\msi\buildrelease.bat`` uses different directories for AMD64 and ARM64 builds.
Loading

0 comments on commit a0a19e8

Please sign in to comment.