Skip to content

Tk.report_callback_exception type annotation breaks subclass override compatibility #15840

@Jesse205

Description

@Jesse205

Problem

The current type annotation for Tk.report_callback_exception in typeshed, introduced in #2498, causes a regression when subclassing tkinter.Tk and overriding the method.

Issue 1: Incompatible override error in pyright

When subclassing Tk and overriding report_callback_exception with the correct runtime signature, pyright reports an incompatible method override error.

Code:

from tkinter import Tk
from types import TracebackType
from typing import override


class App(Tk):
    @override
    def report_callback_exception(
        self,
        exc_type: type[BaseException],
        exc_value: BaseException,
        exc_traceback: TracebackType | None,
    ):
        pass

pyright output:

(report-callback-exception) PS G:\programming\python\lab\report_callback_exception> pyright
g:\programming\python\lab\report_callback_exception\main.py
  g:\programming\python\lab\report_callback_exception\main.py:8:9 - error: Method "report_callback_exception" overrides class "Tk" in an incompatible manner
    Positional parameter count mismatch; base method has 3, but override has 4
    Parameter 2 type mismatch: base parameter is type "BaseException", override parameter is type "type[BaseException]"
    Parameter 3 type mismatch: base parameter is type "TracebackType | None", override parameter is type "BaseException"
      Type "BaseException" is not assignable to type "type[BaseException]"
      Type "TracebackType | None" is not assignable to type "BaseException"
        "TracebackType" is not assignable to "BaseException" (reportIncompatibleMethodOverride)
1 error, 0 warnings, 0 informations

Issue 2: Missing error on invalid manual call

Conversely, pyright does not report an error when manually calling Tk.report_callback_exception with the wrong signature, even though the code fails at runtime.

Code:

from tkinter import Tk
import sys


def main():
    try:
        print(0 / 0)
    except Exception:
        exc_type, exc_value, exc_traceback = sys.exc_info()
        assert exc_type is not None
        assert exc_value is not None
        Tk.report_callback_exception(exc_type, exc_value, exc_traceback)

Runtime error:

(report-callback-exception) PS G:\programming\python\lab\report_callback_exception> & g:\programming\python\lab\report_callback_exception\.venv\Scripts\python.exe g:/programming/python/lab/report_callback_exception/main.py
Traceback (most recent call last):
  File "g:\programming\python\lab\report_callback_exception\main.py", line 7, in main
    0 / 0
    ~~^~~
ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "g:\programming\python\lab\report_callback_exception\main.py", line 16, in <module>
    main()
    ~~~~^^
  File "g:\programming\python\lab\report_callback_exception\main.py", line 12, in main
    Tk.report_callback_exception(exc_type, exc_value, exc_traceback)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: Tk.report_callback_exception() missing 1 required positional argument: 'tb'

pyright output:

(report-callback-exception) PS G:\programming\python\lab\report_callback_exception> pyright
0 errors, 0 warnings, 0 informations

Expected behavior

The type annotation should match the actual runtime signature as used in practice.

Additional context

srittau said in #1767 (comment):

"This looks more like a mypy problem to me. It is somehow expecting an additional self argument here."

If that is indeed the case, I think we should revert the type annotation for report_callback_exception and report the error to mypy instead, because the root cause is not here.

The above statement is irrelevant to this issue.

mypy's error when assigning to a method is intentional, therefore #1767 is not an issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions