From 1de7a4459201dd25a5dcc1ad352e0b97e5a34773 Mon Sep 17 00:00:00 2001 From: Joshua Herman <30265+zitterbewegung@users.noreply.github.com> Date: Mon, 20 May 2024 16:02:07 -0400 Subject: [PATCH] Fix the fraction module so that __rpow__ works on arbitrary classes. The fraction module implicitly casted float if __rpow__ was implemented in your class when raising a fraction to a power. Now it isn't done but will raise an exception if __rpow__ isn't implemented. --- Doc/library/functions.rst | 10 +++++++--- Lib/fractions.py | 4 +++- Misc/ACKS | 1 + .../2024-05-20-13-48-37.gh-issue-119189.dhJVs5.rst | 3 +++ 4 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-05-20-13-48-37.gh-issue-119189.dhJVs5.rst diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 0c7ef67774cd05..3986ace02b561a 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -608,9 +608,13 @@ are always available. They are listed here in alphabetical order. will be used for both the global and the local variables. If *globals* and *locals* are given, they are used for the global and local variables, respectively. If provided, *locals* can be any mapping object. Remember - that at the module level, globals and locals are the same dictionary. If exec - gets two separate objects as *globals* and *locals*, the code will be - executed as if it were embedded in a class definition. + that at the module level, globals and locals are the same dictionary. + + .. note:: + + Most users should just pass a *globals* argument and never *locals*. + If exec gets two separate objects as *globals* and *locals*, the code + will be executed as if it were embedded in a class definition. If the *globals* dictionary does not contain a value for the key ``__builtins__``, a reference to the dictionary of the built-in module diff --git a/Lib/fractions.py b/Lib/fractions.py index f8c6c9c438c737..e71ef58f18b3db 100644 --- a/Lib/fractions.py +++ b/Lib/fractions.py @@ -875,8 +875,10 @@ def __pow__(a, b): # A fractional power will generally produce an # irrational number. return float(a) ** float(b) - else: + elif isinstance(b, (float, complex)): return float(a) ** b + else: + return NotImplemented def __rpow__(b, a): """a ** b""" diff --git a/Misc/ACKS b/Misc/ACKS index eaa7453aaade3e..a7cd7c9992c91f 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -751,6 +751,7 @@ Kasun Herath Chris Herborth Ivan Herman Jürgen Hermann +Joshua Jay Herman Gary Herron Ernie Hershey Thomas Herve diff --git a/Misc/NEWS.d/next/Library/2024-05-20-13-48-37.gh-issue-119189.dhJVs5.rst b/Misc/NEWS.d/next/Library/2024-05-20-13-48-37.gh-issue-119189.dhJVs5.rst new file mode 100644 index 00000000000000..c39ccc0fdce61a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-05-20-13-48-37.gh-issue-119189.dhJVs5.rst @@ -0,0 +1,3 @@ +This fixes a situation where raising a class with rpow in the class calling +the exponent operator to raise it to the power of that class to not cast it +as a float.