Closed
Description
Bug report
Bug description:
When using the **
operator with a Fraction as a base and an object that implements __rpow__
as an exponent the fraction gets wrongfully casted into a float before being passed to __rpow__
from fractions import Fraction
foo = Fraction(4, 3)
class One:
def __rpow__(self, other):
return other
bar = foo**One()
print(bar)
print(type(bar))
Expected Output
4/3
<class 'fractions.Fraction'>
Actual Output:
1.3333333333333333
<class 'float'>
Tested with Python 3.12.3
CPython versions tested on:
3.12
Operating systems tested on:
macOS
Linked PRs
- gh-119189: Add more tests for mixed Fraction arithmetic #119236
- gh-119189: Fix the fraction module so that __rpow__ works on arbitrary classes. #119242
- [3.13] gh-119189: Add more tests for mixed Fraction arithmetic (GH-119236) #119255
- [3.12] gh-119189: Add more tests for mixed Fraction arithmetic (GH-119236) #119256
- gh-119189: Add yet more tests for mixed Fraction arithmetic #119298
- [3.13] gh-119189: Add yet more tests for mixed Fraction arithmetic (GH-119298) #119346
- [3.12] gh-119189: Add yet more tests for mixed Fraction arithmetic (GH-119298) #119347
- [3.12] gh-119189: Fix the power operator for Fraction (GH-119242) #119835
- [3.13] gh-119189: Fix the power operator for Fraction (GH-119242) #119836
Metadata
Metadata
Assignees
Projects
Milestone
Relationships
Development
No branches or pull requests
Activity
zitterbewegung commentedon May 20, 2024
I'm investigating this.
zitterbewegung commentedon May 20, 2024
Reproduced under Linux (Ubuntu). I am working on a Fix (I'm in the sprint workshop)
MojoVampire commentedon May 20, 2024
It's a mistake in the implementation of
Fraction.__pow__
; rather than returningNotImplemented
when the type of the exponent is unrecognized and letting the other type handle it through__rpow__
normally, it intentionally doesreturn float(a) ** b
(wherea
is the name given toself
).It does something similar when a
Fraction
is raised to the power of another non-one denominatorRational
(return float(a) ** float(b)
), but it at least makes more sense there (the comments note that raising a fraction to a fraction generally produces an irrational number, which can't be represented as a fraction in the first place).MojoVampire commentedon May 20, 2024
Is anyone working on a fix? If not, this is an easy one, I can do it.
I worry slightly about possible breakage of existing code, but:
__rpow__
provider can always revert to the old behavior manually (they don't even need it to be version-specific; if they detect aFraction
, which can't be given right now, they convert tofloat
; on older Python, they'll never see aFraction
in the first place)zitterbewegung commentedon May 20, 2024
@MojoVampire I am working on a fix I'm in the cpython sprint.
MojoVampire commentedon May 20, 2024
@zitterbewegung: Same. I'm the guy standing up cause my back is borked. Fix is pretty easy:
replacing the existing final line. Tests are always the pain. I'll review when you're done.
retooth2 commentedon May 20, 2024
For context: I stumbled over the bug when implementing a wrapper number class for exact precision arithmetic that holds the data as a symbolic expression (so e.g. irrational numbers can be used in calculations without error). The class is designed to work with all builtin number types, e.g.
My class is built on the sympy package that does similar things on its own, so this should also be relevant to them.
Anyway: Thanks for the quick response, I really appreciate it.
Best,
Fabian
pythongh-119189: Add more tests for mixed Fraction arithmetic
serhiy-storchaka commentedon May 20, 2024
I worked on this today. The issue itself may be not difficult, but I noticed that tests do not cover many cases in mixed Fraction arithmetic. #119236 adds many new tests, so we will see what other side effect our changes can cause.
zitterbewegung commentedon May 20, 2024
@serhiy-storchaka I will look at this with @MojoVampire to see if there are any additional issues.
MojoVampire commentedon May 20, 2024
I'd suggest the news entry simplify to something like:
Keeps it focused on what was fixed.
zitterbewegung commentedon May 20, 2024
With this fix I see a test failure when manually putting in the new test_fractions code in
#119236
======================================================================
FAIL: testMixedPower (test.test_fractions.FractionTest.testMixedPower)
Traceback (most recent call last):
File "/Users/r2q2/Projects/cpython/Lib/test/test_fractions.py", line 903, in testMixedPower
self.assertTypedEquals(F(3, 2) ** Rect(2, 0), Polar(2.25, 0.0))
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/r2q2/Projects/cpython/Lib/test/test_fractions.py", line 282, in assertTypedEquals
self.assertEqual(expected, actual)
~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^
AssertionError: Polar(Fraction(9, 4), 0.0) != Polar(2.25, 0.0)
Ran 45 tests in 0.038s
FAILED (failures=1)
test test_fractions failed
test_fractions failed (1 failure)
== Tests result: FAILURE ==
1 test failed:
test_fractions
Total duration: 97 ms
Total tests: run=45 failures=1
Total test files: run=1/1 failed=1
Result: FAILURE
17 remaining items
[3.13] gh-119189: Add yet more tests for mixed Fraction arithmetic (G…
gh-119189: Fix the power operator for Fraction (GH-119242)
pythongh-119189: Fix the power operator for Fraction (pythonGH-119242)
pythongh-119189: Fix the power operator for Fraction (pythonGH-119242)
serhiy-storchaka commentedon May 31, 2024
See also #119838.
pythongh-119189: Fix the power operator for Fraction (pythonGH-119242)
[3.12] gh-119189: Fix the power operator for Fraction (GH-119242) (GH…
[3.13] gh-119189: Fix the power operator for Fraction (GH-119242) (GH…
pythongh-119189: Add more tests for mixed Fraction arithmetic (python…
pythongh-119189: Add yet more tests for mixed Fraction arithmetic (py…
pythongh-119189: Fix the power operator for Fraction (pythonGH-119242)