diff --git a/stdlib/_ctypes.pyi b/stdlib/_ctypes.pyi index 36540172ab95..fe9f0eb03f97 100644 --- a/stdlib/_ctypes.pyi +++ b/stdlib/_ctypes.pyi @@ -82,6 +82,13 @@ class _SimpleCData(_CData, Generic[_T]): # The TypeVar can be unsolved here, # but we can't use overloads without creating many, many mypy false-positive errors def __init__(self, value: _T = ...) -> None: ... # pyright: ignore[reportInvalidTypeVarUse] + @overload + def __get__(self, __instance: None, __owner: type[Any] | None) -> Self: ... + @overload + def __get__(self, __instance: Any, __owner: type[_StructUnionBase]) -> _T: ... + @overload + def __get__(self, __instance: Any, __owner: type[Any] | None) -> Self: ... + def __set__(self, __instance: Any, __value: _T) -> None: ... class _CanCastTo(_CData): ... class _PointerLike(_CanCastTo): ... diff --git a/test_cases/stdlib/check_ctypes.py b/test_cases/stdlib/check_ctypes.py new file mode 100644 index 000000000000..de94fd525190 --- /dev/null +++ b/test_cases/stdlib/check_ctypes.py @@ -0,0 +1,45 @@ +# pyright: reportUninitializedInstanceVariable=false + +from __future__ import annotations + +import ctypes +from typing import Any +from typing_extensions import assert_type + + +class Annotated(ctypes.Structure): + _fields_ = [("i", ctypes.c_int), ("f", ctypes.c_float)] + i: ctypes.c_int + f: ctypes.c_float + + +class NoAnnotation(ctypes.Structure): + _fields_ = [("i", ctypes.c_int), ("f", ctypes.c_float)] + + +class NonCType: + i: ctypes.c_int + f: ctypes.c_float + + +assert_type(ctypes.c_int().value, int) +ctypes.c_int() + 2 # type: ignore + +assert_type(ctypes.c_float().value, float) +ctypes.c_float() + 2 # type: ignore + +# All passes; all access are Any +assert_type(NoAnnotation().x + 2, Any) +assert_type(NoAnnotation().vec.x + 2, Any) + +Annotated.x.value + 2 # type: ignore +Annotated.x + 2 # type: ignore +assert_type(Annotated().i, int) +Annotated().i.value + 2 # type: ignore +assert_type(Annotated().f, float) +Annotated().f.value + 3.14 # type: ignore + +assert_type(NonCType.i.value, int) +NonCType.i + 2 # type: ignore +NonCType().i + 2 # type: ignore +assert_type(NonCType().i.value, int) diff --git a/tests/stubtest_allowlists/py3_common.txt b/tests/stubtest_allowlists/py3_common.txt index 1ddc4771f634..5b1053f6d8f4 100644 --- a/tests/stubtest_allowlists/py3_common.txt +++ b/tests/stubtest_allowlists/py3_common.txt @@ -13,6 +13,8 @@ _collections_abc.KeysView.__reversed__ _collections_abc.ValuesView.__reversed__ _csv.Dialect.__init__ # C __init__ signature is inaccurate _ctypes.CFuncPtr # stubtest erroneously thinks it can't be subclassed +_ctypes._SimpleCData.__get__ # Does not exist on runtime object +_ctypes._SimpleCData.__set__ # Does not exist on runtime object _threading_local.local.__new__ ast.Bytes.__new__ ast.Ellipsis.__new__ @@ -37,6 +39,8 @@ ctypes.memmove # CFunctionType ctypes.memset # CFunctionType ctypes.string_at # docstring argument name is wrong ctypes.wstring_at # docstring argument name is wrong +ctypes._SimpleCData.__get__ # Does not exist on runtime object +ctypes._SimpleCData.__set__ # Does not exist on runtime object fractions.Fraction.__new__ # overload is too complicated for stubtest to resolve ftplib.FTP.trust_server_pasv_ipv4_address # Dangerous to use, intentionally undocumented, intentionally missing from typeshed. #6154 functools.cached_property.__set__ # Stub is a white lie; see comments in the stub