Skip to content

Mypy signals error with Protocol and __rpow__ method with three arguments #10786

Description

@posita

Okay, this is a head-scratcher. 😕

To Reproduce

# test_case.py
from typing import Protocol, overload, runtime_checkable
@runtime_checkable
class PowableProto(Protocol):
    @overload
    def __pow__(self, other: "PowableProto") -> "PowableProto":
        ...
    @overload
    def __pow__(self, other: "PowableProto", modulo: "PowableProto") -> "PowableProto":  # <- fine
        ...
    @overload
    def __rpow__(self, other: "PowableProto") -> "PowableProto":
        ...
    @overload
    def __rpow__(self, other: "PowableProto", modulo: "PowableProto") -> "PowableProto":  # <- this (of all things) breaks
        ...
    @overload
    def __rpOw__(self, other: "PowableProto") -> "PowableProto":
        ...
    @overload
    def __rpOw__(self, other: "PowableProto", modulo: "PowableProto") -> "PowableProto":  # <- fine
        ...
% mypy --version
mypy 0.910
% mypy --config-file=/dev/null test_case.py
/dev/null: No [mypy] section in config file
test_case.py:15: error: Invalid signature "def (test_case.PowableProto, test_case.PowableProto, test_case.PowableProto) -> test_case.PowableProto"
Found 1 error in 1 file (checked 1 source file)

Expected vs. Actual Behavior

I would expect at least consistent behavior among the overridden methods. This only crops up with __rpow__ for some reason. (I have tested many others.)

Your Environment

  • Mypy version used: 0.910
  • Mypy command-line flags: --config-file=/dev/null (i.e., force default configuration)
  • Mypy configuration options from mypy.ini (and other config files): N/A
  • Python version used: Python 3.9.6 (from python --version)
  • Operating system and version: Darwin Kernel Version 19.6.0: Thu May 6 00:48:39 PDT 2021; root:xnu-6153.141.33~1/RELEASE_X86_64 (from uname -v)

Activity

  1. posita commented on Jul 8, 2021

    @posita
    ContributorAuthor

    Actually, scratch that. Here's a simpler test case that still breaks on __rpow__ (and only on __rpow__):

    # test_case2.py
    from typing import Protocol, runtime_checkable
    @runtime_checkable
    class PowableProto(Protocol):
        def __pow__(self, other: "PowableProto", modulo: "PowableProto") -> "PowableProto":  # <- fine
            ...
        def __rpow__(self, other: "PowableProto", modulo: "PowableProto") -> "PowableProto":  # <- this breaks
            ...

    This (in the style of using ellipses for default arguments in stub files) works, though:

    # test_case3.py
    from typing import Protocol, runtime_checkable
    @runtime_checkable
    class PowableProto(Protocol):
        def __pow__(self, other: "PowableProto", modulo: "PowableProto" = ...) -> "PowableProto":  # <- this now breaks
            ...
        def __rpow__(self, other: "PowableProto", modulo: "PowableProto" = ...) -> "PowableProto":  # <- this still breaks
            ...

    The callout of __rpow__ still seems…weird. 🤨

  2. changed the title [-]Protocol doesn't like second @overload-ed __rpow__ method—and *only* the second @overload-ed __rpow__ method[/-] [+]Mypy signals error with Protocol and __rpow__ method with three arguments[/+] on Jul 8, 2021
  3. ilevkivskyi commented on Nov 16, 2022

    @ilevkivskyi
    Member

    I don't think it is related to recursive types. Mypy has strong requirements for Python special methods, and FWIW I think it is fine to relax those for protocols, probably an easy fix.

  4. added a commit that references this issue on Sep 3, 2023
    bd35198
  5. Cnoor0171 commented on Dec 5, 2023

    @Cnoor0171

    I think the error is correct in this case, isn't it? The three argument version of __pow__ is called when the built-in pow function is called, but the python docs explicitly mention that __rpow__ does not use the three argument version. From https://docs.python.org/3/reference/datamodel.html

    Note that ternary pow() will not try calling rpow() (the coercion rules would become too complicated).

  6. jorenham commented on Jun 29, 2026

    @jorenham
    Contributor

    Since Python 3.14, the 3-argument __rpow__ for ternary pow is supported: python/cpython#130251. The 3.14 relnotes also mention this: https://docs.python.org/3/whatsnew/3.14.html#built-ins

  7. posita commented on Jun 30, 2026

    @posita
    ContributorAuthor

    Since Python 3.14, the 3-argument __rpow__ for ternary pow is supported: python/cpython#130251. The 3.14 relnotes also mention this: https://docs.python.org/3/whatsnew/3.14.html#built-ins

    Hmmm...then maybe @Cnoor0171 was right with #10786 (comment) ? My first two test cases still produce errors:

    % /python3 --version
    Python 3.14.6
    % mypy --version
    mypy 2.1.0 (compiled: yes)
    % mypy test_case.py test_case2.py test_case3.py
    test_case.py:15: error: Invalid signature "Callable[[PowableProto, PowableProto, PowableProto], PowableProto]"  [misc]
    test_case2.py:7: error: Invalid signature "Callable[[PowableProto, PowableProto, PowableProto], PowableProto]"  [misc]
    Found 2 errors in 2 files (checked 3 source files)

    Sounds like this can be closed as either fixed or as-designed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions