diff --git a/stdlib/@tests/stubtest_allowlists/py314.txt b/stdlib/@tests/stubtest_allowlists/py314.txt index d8ea70b91..6d312dacd 100644 --- a/stdlib/@tests/stubtest_allowlists/py314.txt +++ b/stdlib/@tests/stubtest_allowlists/py314.txt @@ -9,8 +9,6 @@ compression.gzip.GzipFile.readinto compression.gzip.GzipFile.readinto1 compression.gzip.GzipFile.readinto1 compression.gzip.compress -fractions.Fraction.__pow__ -fractions.Fraction.__rpow__ gzip.GzipFile.readinto gzip.GzipFile.readinto1 gzip.compress diff --git a/stdlib/@tests/test_cases/builtins/check_pow.py b/stdlib/@tests/test_cases/builtins/check_pow.py index 448d41ad8..63ca9a896 100644 --- a/stdlib/@tests/test_cases/builtins/check_pow.py +++ b/stdlib/@tests/test_cases/builtins/check_pow.py @@ -1,5 +1,6 @@ from __future__ import annotations +import sys from decimal import Decimal from fractions import Fraction from typing import Any, Literal @@ -47,9 +48,6 @@ assert_type(pow(complex(6), 6.2), complex) assert_type(complex(6) ** 6.2, complex) assert_type(pow(complex(9), 7.3, None), complex) -# pyright infers Fraction | float | complex, while mypy infers Fraction. -# This is probably because of differences in @overload handling. -assert_type(pow(Fraction(), 4, None), Fraction) # pyright: ignore[reportAssertTypeFailure] assert_type(Fraction() ** 4, Fraction) assert_type(pow(Fraction(3, 7), complex(1, 8)), complex) @@ -85,12 +83,22 @@ assert_type(pow(4.7, 9.2, None), Any) # See #7046 -- float for a positive 1st arg, complex otherwise assert_type((-95) ** 8.42, Any) +# Fraction.__pow__/__rpow__ with modulo parameter +# With the None parameter, we get the correct type, but with a non-None parameter, we receive TypeError +if sys.version_info >= (3, 14): + # pyright infers Fraction | float | complex, while mypy infers Fraction. + # This is probably because of differences in @overload handling. + assert_type(pow(Fraction(3, 4), 2, None), Fraction) # pyright: ignore[reportAssertTypeFailure] + # Non-none modulo should fail + pow(Fraction(3, 4), 2, 1) # type: ignore[misc] +else: + pow(Fraction(), 5, 8) # type: ignore + # All of the following cases should fail a type-checker. pow(1.9, 4, 6) # type: ignore pow(4, 7, 4.32) # type: ignore pow(6.2, 5.9, 73) # type: ignore pow(complex(6), 6.2, 7) # type: ignore -pow(Fraction(), 5, 8) # type: ignore Decimal("8.7") ** 3.14 # type: ignore # TODO: This fails at runtime, but currently passes mypy and pyright: diff --git a/stdlib/fractions.pyi b/stdlib/fractions.pyi index 83592eb58..16259fcfa 100644 --- a/stdlib/fractions.pyi +++ b/stdlib/fractions.pyi @@ -107,16 +107,31 @@ class Fraction(Rational): def __rdivmod__(a, b: int | Fraction) -> tuple[int, Fraction]: ... @overload def __rdivmod__(a, b: float) -> tuple[float, Fraction]: ... - @overload - def __pow__(a, b: int) -> Fraction: ... - @overload - def __pow__(a, b: float | Fraction) -> float: ... - @overload - def __pow__(a, b: complex) -> complex: ... - @overload - def __rpow__(b, a: float | Fraction) -> float: ... - @overload - def __rpow__(b, a: complex) -> complex: ... + if sys.version_info >= (3, 14): + @overload + def __pow__(a, b: int, modulo: None = None) -> Fraction: ... + @overload + def __pow__(a, b: float | Fraction, modulo: None = None) -> float: ... + @overload + def __pow__(a, b: complex, modulo: None = None) -> complex: ... + else: + @overload + def __pow__(a, b: int) -> Fraction: ... + @overload + def __pow__(a, b: float | Fraction) -> float: ... + @overload + def __pow__(a, b: complex) -> complex: ... + if sys.version_info >= (3, 14): + @overload + def __rpow__(b, a: float | Fraction, modulo: None = None) -> float: ... + @overload + def __rpow__(b, a: complex, modulo: None = None) -> complex: ... + else: + @overload + def __rpow__(b, a: float | Fraction) -> float: ... + @overload + def __rpow__(b, a: complex) -> complex: ... + def __pos__(a) -> Fraction: ... def __neg__(a) -> Fraction: ... def __abs__(a) -> Fraction: ...