Subclassing `ObjectDoesNotExist` and forwarding `**kwargs` fails mypy

Đang mở
#737 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
45/100
Loại issue
Lỗi
Độ rõ ràng
Khá rõ ràng
Mức độ hoạt động
Ít trao đổi
Công nghệ
python

Hướng nghiên cứu

Start with src/libtmux/exc.py and inspect the typed init signatures for ObjectDoesNotExist and MultipleObjectsReturned. Reproduce the failure with the provided subclass and mypy, then evaluate the documented catch-all and migration-note options. Done means the chosen behavior is documented or implemented without losing direct checking of query and count.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

Summary

ObjectDoesNotExist.__init__ and MultipleObjectsReturned.__init__ gained typed keyword-only parameters in v0.62.0. A subclass that forwards **kwargs to super().__init__ — the ordinary way to extend an exception — no longer type-checks, because mypy validates the unpacked mapping against every declared keyword parameter. Runtime behavior is unaffected; only type-checking fails.

tmuxp hits this in tmuxp/exc.py. It is currently pinned to libtmux 0.61.0, so the failure appears the moment that pin moves.

Reproduction
from libtmux.exc import ObjectDoesNotExist


class SessionMissing(ObjectDoesNotExist):
    def __init__(self, *args: object, **kwargs: object) -> None:
        super().__init__("no session", *args, **kwargs)
$ mypy repro.py
Expected

Type-checks. The call is correct at runtime, and forwarding **kwargs is the conventional way to subclass an exception.

Actual
error: Argument 3 to "__init__" of "ObjectDoesNotExist" has incompatible type "**dict[str, object]"; expected "Mapping[str, Any] | None"  [arg-type]

Widening the subclass to **kwargs: t.Any silences it, but that is a downstream workaround for an upstream signature change, and it gives up the subclass's own annotation.

Environment
libtmux  0.62.0
mypy     2.3.0
Python   3.14.6
Evidence

Against tmuxp's checkout, changing only the installed libtmux:

$ uv pip install 'libtmux==0.61.0' && uv run mypy src
Success: no issues found in 41 source files
$ uv pip install 'libtmux==0.62.0' && uv run mypy src
src/tmuxp/exc.py:86: error: Argument 3 to "__init__" of "ObjectDoesNotExist" has incompatible type "**dict[str, object]"; expected "Mapping[str, Any] | None"  [arg-type]
Found 1 error in 1 file (checked 41 source files)
Proposal

Two options, neither obviously right.

Accept a **kwargs catch-all upstream

Add **kwargs: t.Any to both __init__ signatures and raise TypeError for anything unrecognized, so a typo is still caught.

This was measured and does not fix the reported error: mypy still binds the unpacked mapping against query, so the catch-all changes nothing for the subclass. It also replaces CPython's own message — which suggests the intended keyword — with a hand-written one:

# CPython
TypeError: __init__() got an unexpected keyword argument 'qeury'. Did you mean 'query'?

# hand-written
TypeError: unexpected keyword argument: qeury

Recorded here so the next person does not re-derive it.

Document it as a deliberate tightening

Leave the signatures alone and add a MIGRATION note telling downstream subclasses to annotate **kwargs: t.Any. This keeps query and count statically checked for direct callers, which is what made them worth adding.

References
Ngôn ngữ chính
Python
Star
1.2k
Fork
127
Merge trung bình
2 giờ 13 phút
Pull request đã merge (30 ngày)
1

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của tmux-python/libtmux

Tất cả issue của tmux-python/libtmux

Issue tương tự

Thêm issue về Python

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.