bpo-39274: Ensure Fraction.__bool__() returns a bool (GH-18017)

Some numerator types used (specifically NumPy) decides to not
return a Python boolean for the "a != b" operation. Using the equivalent
call to bool() guarantees a bool return also for such types.
This commit is contained in:
Sebastian Berg 2020-02-06 06:54:05 -08:00 committed by GitHub
parent 3f563cea56
commit 427c84f13f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 41 additions and 1 deletions

View File

@ -625,7 +625,9 @@ class Fraction(numbers.Rational):
def __bool__(a):
"""a != 0"""
return a._numerator != 0
# bpo-39274: Use bool() because (a._numerator != 0) can return an
# object which is not a bool.
return bool(a._numerator)
# support for pickling, copy, and deepcopy

View File

@ -6,6 +6,7 @@ import math
import numbers
import operator
import fractions
import functools
import sys
import unittest
import warnings
@ -322,6 +323,42 @@ class FractionTest(unittest.TestCase):
self.assertTypedEquals(0.1+0j, complex(F(1,10)))
def testBoolGuarateesBoolReturn(self):
# Ensure that __bool__ is used on numerator which guarantees a bool
# return. See also bpo-39274.
@functools.total_ordering
class CustomValue:
denominator = 1
def __init__(self, value):
self.value = value
def __bool__(self):
return bool(self.value)
@property
def numerator(self):
# required to preserve `self` during instantiation
return self
def __eq__(self, other):
raise AssertionError("Avoid comparisons in Fraction.__bool__")
__lt__ = __eq__
# We did not implement all abstract methods, so register:
numbers.Rational.register(CustomValue)
numerator = CustomValue(1)
r = F(numerator)
# ensure the numerator was not lost during instantiation:
self.assertIs(r.numerator, numerator)
self.assertIs(bool(r), True)
numerator = CustomValue(0)
r = F(numerator)
self.assertIs(bool(r), False)
def testRound(self):
self.assertTypedEquals(F(-200), round(F(-150), -2))
self.assertTypedEquals(F(-200), round(F(-250), -2))

View File

@ -0,0 +1 @@
``bool(fraction.Fraction)`` now returns a boolean even if (numerator != 0) does not return a boolean (ex: numpy number).