python / python/cpython

`dataclasses`: Synthetic `__init__` method on dataclass has broken `ClassVar` annotation under some conditions.

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

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

stdlib topic-dataclasses type-bug
Ngôn ngữ chính
Python
Star
77.2k
Fork
35.9k
Chỉ số merge pull request
Chỉ số pull request đang chờ

Mô tả

Bug report

Bug description:

When using automatically-stringified annotations (from __future__ import annotations), typing_extensions.ClassVar is not treated the same as typing.ClassVar even though those two objects are identical. Specifically, the dataclasses.dataclass-produced __init__ method does not exclude typing_extensions.ClassVar-wrapped variables from its annotations, but does exclude typing.ClassVar-wrapped variables from its annotations. Among other problems, this causes typing.get_type_hints to choke.

Reproducer below:

from __future__ import annotations

import dataclasses as dcls
import inspect
import typing
import typing_extensions as typx


assert typing.ClassVar is typx.ClassVar


@dcls.dataclass
class Foo:

    y: int
    x: typing.ClassVar[ int ] = 1


print( "\n=== typing.ClassVar (ok) ===" )

print( 'anno', Foo.__init__.__annotations__ )
print( 'inspect', inspect.get_annotations( Foo.__init__, eval_str = True ) )
print( 'typing', typing.get_type_hints( Foo.__init__ ) )
print( 'typx', typx.get_type_hints( Foo.__init__ ) )


@dcls.dataclass
class Bar:

    y: int
    x: typx.ClassVar[ int ] = 1


print( "\n=== typing_extensions.ClassVar (breaks) ===" )

print( 'anno', Bar.__init__.__annotations__ )
print( 'inspect', inspect.get_annotations( Bar.__init__, eval_str = True ) )
print( 'typing', typing.get_type_hints( Bar.__init__ ) )
print( 'typx', typx.get_type_hints( Bar.__init__ ) )

This results in the following output:

=== typing.ClassVar (ok) ===
anno {'y': 'int', 'return': None}
inspect {'y': <class 'int'>, 'return': None}
typing {'y': <class 'int'>, 'return': <class 'NoneType'>}
typx {'y': <class 'int'>, 'return': <class 'NoneType'>}

=== typing_extensions.ClassVar (breaks) ===
anno {'y': 'int', 'x': 'typx.ClassVar[int]', 'return': None}
inspect {'y': <class 'int'>, 'x': typing.ClassVar[int], 'return': None}
Traceback (most recent call last):
  File "/home/me/src/somepkg/bugs/dcls-classvar-hints.py", line 38, in <module>
    print( 'typing', typing.get_type_hints( Bar.__init__ ) )
  File "/usr/lib/python3.10/typing.py", line 1871, in get_type_hints
    value = _eval_type(value, globalns, localns)
  File "/usr/lib/python3.10/typing.py", line 327, in _eval_type
    return t._evaluate(globalns, localns, recursive_guard)
  File "/usr/lib/python3.10/typing.py", line 693, in _evaluate
    type_ = _type_check(
  File "/usr/lib/python3.10/typing.py", line 167, in _type_check
    raise TypeError(f"{arg} is not valid as type argument")
TypeError: typing.ClassVar[int] is not valid as type argument

(Credit to @Daraan for helping me pinpoint the problem.)

This is reproducible on both Python 3.10 and 3.13.

Possibly related to https://github.com/python/cpython/issues/89687.

CPython versions tested on:

3.10, 3.13

Operating systems tested on:

No response

Linked PRs
  • gh-134073
  • gh-140541

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.

Hướng nghiên cứu

Bắt đầu với reproducer và theo dõi cách dataclasses.dataclass xây dựng init.annotations cho các annotation ClassVar, bằng cách so sánh typing.ClassVar với typing_extensions.ClassVar. Xác nhận fix bằng cách kiểm tra rằng annotation được tạo ra loại trừ trường ClassVar và typing.get_type_hints hoạt động mà không phát sinh ngoại lệ; issue liệt kê các PR liên quan gh-134073 và gh-140541.

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
backend
Loại issue
Lỗi
Độ khó
3/5
Thời gian dự kiến
1-2 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
25/100

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.