false positive: classmethod constructor on generic class
Chưa có ai nhận issue này.
- Ngôn ngữ chính
- Python
- Star
- 20.6k
- Fork
- 3.3k
- Merge trung bình
- 1 ngày 18 giờ
- Pull request đã merge (30 ngày)
- 54
Mô tả
I'm inclined to think this is a bug, but could be argued it's a missing feature.
How to reproduce
# makes_bug.py
from typing import Generic, Type, TypeVar
T = TypeVar('T')
class Foo(Generic[T]):
def __init__(self, value: T) -> None: ...
@classmethod
def construct(cls) -> Foo[str]:
return cls('bar')
Expected outcome
This code should pass type checks.
Actual outcome
mypy, to my great surprise, fails:
$ python --version
Python 3.8.1
$ mypy --version
mypy 0.790+dev.65186ae1e23fd44f1d7e6aa2c4458bdf55640742
$ mypy src/makes_bug.py
makes_bug.py:11: error: Incompatible return value type (got "Foo[T]", expected "Foo[str]")
makes_bug.py:11: error: Argument "value" to "Foo" has incompatible type "str"; expected "T"
Found 2 errors in 1 file (checked 1 source file)
Workaround
Changing line 10 to def construct(cls: Type[Foo]) -> Foo[str]: fixes it; or, probably more or less equivalently, def construct(cls: Type[Foo[Any]]) -> Foo[str]:.
Investigation / suggested fix
Adding reveal_type(cls) indicates that cls is inferred to have type Foo[T], which cannot return a Foo[str].
It's not clear to me why classmethods should have the lead argument inferred to a bound type. I'd propose that my workaround be made a default: class methods should infer the type of the lead argument type as the unbound class type, or bound with all Anys.
I'd imagine the change would go here: https://github.com/python/mypy/blob/65186ae1e23fd44f1d7e6aa2c4458bdf55640742/mypy/semanal.py#L609,L610
or (more likely) in the referenced method class_type():
https://github.com/python/mypy/blob/65186ae1e23fd44f1d7e6aa2c4458bdf55640742/mypy/semanal.py#L4790,L4791
Happy to take a stab at it, but wanted to solicit some feedback first. This is a complex system and it's possible I'm missing some potential consequence here.
Hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- 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.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Hướng nghiên cứu
Bắt đầu với phần tái hiện classmethod generic trong makes_bug.py và kiểm tra mypy/semanal.py tại các dòng được tham chiếu, đặc biệt là class_type(). Sử dụng reveal_type(cls) và chạy mypy trên ví dụ để xác nhận kiểu được suy luận. Được xem là hoàn tất khi ví dụ vượt qua kiểm tra kiểu mà không cần workaround Type[Foo], đồng thời vẫn giữ nguyên hành vi generic hiện có.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- python
- Lĩnh vực
- devtools
- Loại issue
- Lỗi
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức độ hoạt động
- Đình trệ
- Độ rõ ràng
- Khá rõ ràng
- Mức phù hợp với người mới
- 35/100