8000 bpo-39274: Ensure Fraction.__bool__() returns a bool (GH-18017) · python/cpython@427c84f · GitHub
[go: up one dir, main page]

Skip to content

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 427c84f

Browse files
authored
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.
1 parent 3f563ce commit 427c84f

File tree

3 files changed

+41
-1
lines changed

3 files changed

+41
-1
lines changed

Lib/fractions.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,9 @@ def __ge__(a, b):
625625

626626
def __bool__(a):
627627
"""a != 0"""
628-
return a._numerator != 0
628+
# bpo-39274: Use bool() because (a._numerator != 0) can return an
629+
# object which is not a bool.
630+
return bool(a._numerator)
629631

630632
# support for pickling, copy, and deepcopy
631633

Lib/test/test_fractions.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import numbers
77
import operator
88
import fractions
9+
import functools
910
import sys
1011
import unittest
1112
import warnings
@@ -322,6 +323,42 @@ def testConversions(self):
322323

323324
self.assertTypedEquals(0.1+0j, complex(F(1,10)))
324325

326+
def testBoolGuarateesBoolReturn(self):
327+
# Ensure that __bool__ is used on numerator which guarantees a bool
328+
# return. See also bpo-39274.
329+
@functools.total_ordering
330+
class CustomValue:
331+
denominator = 1
332+
333+
def __init__(self, value):
334+
self.value = value
335+
336+
def __bool__(self):
337+
return bool(self.value)
338+
339+
@property
340+
def numerator(self):
341+
# required to preserve `self` during instantiation
342+
return self
343+
344+
def __eq__(self, other):
345+
raise AssertionError("Avoid comparisons in Fraction.__bool__")
346+
347+
__lt__ = __eq__
348+
349+
# We did not implement all abstract methods, so register:
350+
numbers.Rational.register(CustomValue)
351+
352+
numerator = CustomValue(1)
353+
r = F(numerator)
354+
# ensure the numerator was not lost during instantiation:
355+
self.assertIs(r.numerator, numerator)
356+
self.assertIs(bool(r), True)
357+
358+
numerator = CustomValue(0)
359+
r = F(numerator)
360+
self.assertIs(bool(r), False)
361+
325362
def testRound(self):
326363
self.assertTypedEquals(F(-200), round(F(-150), -2))
327364
self.assertTypedEquals(F(-200), round(F(-250), -2))
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
``bool(fraction.Fraction)`` now returns a boolean even if (numerator != 0) does not return a boolean (ex: numpy number).

0 commit comments

Comments
 (0)
0