bpo-46624: Defer to 3.12: "Remove deprecated support for non-integer values" (GH-31098)

This commit is contained in:
Miro Hrončok 2022-02-03 14:48:13 +01:00 committed by GitHub
parent 674ab66ebd
commit 6baa98e538
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 94 additions and 50 deletions

View file

@ -135,10 +135,15 @@ Functions for integers
values. Formerly it used a style like ``int(random()*n)`` which could produce values. Formerly it used a style like ``int(random()*n)`` which could produce
slightly uneven distributions. slightly uneven distributions.
.. versionchanged:: 3.11 .. deprecated:: 3.10
Automatic conversion of non-integer types is no longer supported. The automatic conversion of non-integer types to equivalent integers is
Calls such as ``randrange(10.0)`` and ``randrange(Fraction(10, 1))`` deprecated. Currently ``randrange(10.0)`` is losslessly converted to
now raise a :exc:`TypeError`. ``randrange(10)``. In the future, this will raise a :exc:`TypeError`.
.. deprecated:: 3.10
The exception raised for non-integral values such as ``randrange(10.5)``
or ``randrange('10')`` will be changed from :exc:`ValueError` to
:exc:`TypeError`.
.. function:: randint(a, b) .. function:: randint(a, b)

View file

@ -282,17 +282,27 @@ class Random(_random.Random):
## -------------------- integer methods ------------------- ## -------------------- integer methods -------------------
def randrange(self, start, stop=None, step=_ONE): def randrange(self, start, stop=None, step=_ONE):
"""Choose a random item from range(stop) or range(start, stop[, step]). """Choose a random item from range(start, stop[, step]).
Roughly equivalent to ``choice(range(start, stop, step))`` This fixes the problem with randint() which includes the
but supports arbitrarily large ranges and is optimized endpoint; in Python this is usually not what you want.
for common cases.
""" """
# This code is a bit messy to make it fast for the # This code is a bit messy to make it fast for the
# common case while still doing adequate error checking. # common case while still doing adequate error checking.
istart = _index(start) try:
istart = _index(start)
except TypeError:
istart = int(start)
if istart != start:
_warn('randrange() will raise TypeError in the future',
DeprecationWarning, 2)
raise ValueError("non-integer arg 1 for randrange()")
_warn('non-integer arguments to randrange() have been deprecated '
'since Python 3.10 and will be removed in a subsequent '
'version',
DeprecationWarning, 2)
if stop is None: if stop is None:
# We don't check for "step != 1" because it hasn't been # We don't check for "step != 1" because it hasn't been
# type checked and converted to an integer yet. # type checked and converted to an integer yet.
@ -302,15 +312,37 @@ class Random(_random.Random):
return self._randbelow(istart) return self._randbelow(istart)
raise ValueError("empty range for randrange()") raise ValueError("empty range for randrange()")
# Stop argument supplied. # stop argument supplied.
istop = _index(stop) try:
istop = _index(stop)
except TypeError:
istop = int(stop)
if istop != stop:
_warn('randrange() will raise TypeError in the future',
DeprecationWarning, 2)
raise ValueError("non-integer stop for randrange()")
_warn('non-integer arguments to randrange() have been deprecated '
'since Python 3.10 and will be removed in a subsequent '
'version',
DeprecationWarning, 2)
width = istop - istart width = istop - istart
istep = _index(step) try:
istep = _index(step)
except TypeError:
istep = int(step)
if istep != step:
_warn('randrange() will raise TypeError in the future',
DeprecationWarning, 2)
raise ValueError("non-integer step for randrange()")
_warn('non-integer arguments to randrange() have been deprecated '
'since Python 3.10 and will be removed in a subsequent '
'version',
DeprecationWarning, 2)
# Fast path. # Fast path.
if istep == 1: if istep == 1:
if width > 0: if width > 0:
return istart + self._randbelow(width) return istart + self._randbelow(width)
raise ValueError(f"empty range in randrange({start}, {stop}, {step})") raise ValueError("empty range for randrange() (%d, %d, %d)" % (istart, istop, width))
# Non-unit step argument supplied. # Non-unit step argument supplied.
if istep > 0: if istep > 0:
@ -320,7 +352,7 @@ class Random(_random.Random):
else: else:
raise ValueError("zero step for randrange()") raise ValueError("zero step for randrange()")
if n <= 0: if n <= 0:
raise ValueError(f"empty range in randrange({start}, {stop}, {step})") raise ValueError("empty range for randrange()")
return istart + istep * self._randbelow(n) return istart + istep * self._randbelow(n)
def randint(self, a, b): def randint(self, a, b):

View file

@ -481,44 +481,50 @@ class SystemRandom_TestBasicOps(TestBasicOps, unittest.TestCase):
self.assertEqual(rint, 0) self.assertEqual(rint, 0)
def test_randrange_errors(self): def test_randrange_errors(self):
raises_value_error = partial(self.assertRaises, ValueError, self.gen.randrange) raises = partial(self.assertRaises, ValueError, self.gen.randrange)
raises_type_error = partial(self.assertRaises, TypeError, self.gen.randrange)
# Empty range # Empty range
raises_value_error(3, 3) raises(3, 3)
raises_value_error(-721) raises(-721)
raises_value_error(0, 100, -12) raises(0, 100, -12)
# Non-integer start/stop
self.assertWarns(DeprecationWarning, raises, 3.14159)
self.assertWarns(DeprecationWarning, self.gen.randrange, 3.0)
self.assertWarns(DeprecationWarning, self.gen.randrange, Fraction(3, 1))
self.assertWarns(DeprecationWarning, raises, '3')
self.assertWarns(DeprecationWarning, raises, 0, 2.71828)
self.assertWarns(DeprecationWarning, self.gen.randrange, 0, 2.0)
self.assertWarns(DeprecationWarning, self.gen.randrange, 0, Fraction(2, 1))
self.assertWarns(DeprecationWarning, raises, 0, '2')
# Zero and non-integer step
raises(0, 42, 0)
self.assertWarns(DeprecationWarning, raises, 0, 42, 0.0)
self.assertWarns(DeprecationWarning, raises, 0, 0, 0.0)
self.assertWarns(DeprecationWarning, raises, 0, 42, 3.14159)
self.assertWarns(DeprecationWarning, self.gen.randrange, 0, 42, 3.0)
self.assertWarns(DeprecationWarning, self.gen.randrange, 0, 42, Fraction(3, 1))
self.assertWarns(DeprecationWarning, raises, 0, 42, '3')
self.assertWarns(DeprecationWarning, self.gen.randrange, 0, 42, 1.0)
self.assertWarns(DeprecationWarning, raises, 0, 0, 1.0)
# Zero step def test_randrange_argument_handling(self):
raises_value_error(0, 42, 0) randrange = self.gen.randrange
raises_type_error(0, 42, 0.0) with self.assertWarns(DeprecationWarning):
raises_type_error(0, 0, 0.0) randrange(10.0, 20, 2)
with self.assertWarns(DeprecationWarning):
# Non-integer stop randrange(10, 20.0, 2)
raises_type_error(3.14159) with self.assertWarns(DeprecationWarning):
raises_type_error(3.0) randrange(10, 20, 1.0)
raises_type_error(Fraction(3, 1)) with self.assertWarns(DeprecationWarning):
raises_type_error('3') randrange(10, 20, 2.0)
raises_type_error(0, 2.71827) with self.assertWarns(DeprecationWarning):
raises_type_error(0, 2.0) with self.assertRaises(ValueError):
raises_type_error(0, Fraction(2, 1)) randrange(10.5)
raises_type_error(0, '2') with self.assertWarns(DeprecationWarning):
raises_type_error(0, 2.71827, 2) with self.assertRaises(ValueError):
randrange(10, 20.5)
# Non-integer start with self.assertWarns(DeprecationWarning):
raises_type_error(2.71827, 5) with self.assertRaises(ValueError):
raises_type_error(2.0, 5) randrange(10, 20, 1.5)
raises_type_error(Fraction(2, 1), 5)
raises_type_error('2', 5)
raises_type_error(2.71827, 5, 2)
# Non-integer step
raises_type_error(0, 42, 3.14159)
raises_type_error(0, 42, 3.0)
raises_type_error(0, 42, Fraction(3, 1))
raises_type_error(0, 42, '3')
raises_type_error(0, 42, 1.0)
raises_type_error(0, 0, 1.0)
def test_randrange_step(self): def test_randrange_step(self):
# bpo-42772: When stop is None, the step argument was being ignored. # bpo-42772: When stop is None, the step argument was being ignored.

View file

@ -0,0 +1 @@
Restore support for non-integer arguments of :func:`random.randrange` and :func:`random.randint`.