diff --git a/stdlib/functools.pyi b/stdlib/functools.pyi index de8e64893..fe36a134f 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -148,6 +148,8 @@ if sys.version_info >= (3, 8): @overload def __get__(self, instance: object, owner: type[Any] | None = None) -> _T: ... def __set_name__(self, owner: type[Any], name: str) -> None: ... + # __set__ is not defined at runtime, but @cached_property is designed to be settable + def __set__(self, instance: object, value: _T) -> None: ... if sys.version_info >= (3, 9): def __class_getitem__(cls, item: Any) -> GenericAlias: ... diff --git a/test_cases/stdlib/check_functools.py b/test_cases/stdlib/check_functools.py new file mode 100644 index 000000000..327e60faa --- /dev/null +++ b/test_cases/stdlib/check_functools.py @@ -0,0 +1,28 @@ +from __future__ import annotations + +import sys + +if sys.version_info >= (3, 8): + from functools import cached_property + from typing_extensions import assert_type + + class A: + def __init__(self, x: int): + self.x = x + + @cached_property + def x(self) -> int: + return 0 + + assert_type(A(x=1).x, int) + + class B: + @cached_property + def x(self) -> int: + return 0 + + def check_cached_property_settable(x: int) -> None: + b = B() + assert_type(b.x, int) + b.x = x + assert_type(b.x, int) diff --git a/tests/stubtest_allowlists/py310.txt b/tests/stubtest_allowlists/py310.txt index a3c77a1b9..00de048a0 100644 --- a/tests/stubtest_allowlists/py310.txt +++ b/tests/stubtest_allowlists/py310.txt @@ -16,6 +16,7 @@ builtins.property.__set_name__ # Doesn't actually exist contextlib.AbstractAsyncContextManager.__class_getitem__ contextlib.AbstractContextManager.__class_getitem__ fractions.Fraction.__new__ # overload is too complicated for stubtest to resolve +functools.cached_property.__set__ # Stub is a while lie; see comments in the stub gettext.install gettext.translation hmac.new # Stub is a white lie; see comments in the stub diff --git a/tests/stubtest_allowlists/py311.txt b/tests/stubtest_allowlists/py311.txt index 12adfda65..2af032c20 100644 --- a/tests/stubtest_allowlists/py311.txt +++ b/tests/stubtest_allowlists/py311.txt @@ -20,6 +20,7 @@ enum.auto.__init__ enum.auto.value fractions.Fraction.__new__ # overload is too complicated for stubtest to resolve ftplib.FTP.trust_server_pasv_ipv4_address +functools.cached_property.__set__ # Stub is a while lie; see comments in the stub ipaddress.IPv4Interface.hostmask ipaddress.IPv6Interface.hostmask ipaddress._BaseNetwork.broadcast_address diff --git a/tests/stubtest_allowlists/py38.txt b/tests/stubtest_allowlists/py38.txt index 307ba1c1e..cb2eb0cd2 100644 --- a/tests/stubtest_allowlists/py38.txt +++ b/tests/stubtest_allowlists/py38.txt @@ -46,6 +46,7 @@ dummy_threading.Thread.native_id dummy_threading.local.__new__ 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 while lie; see comments in the stub gettext.install # codeset default value is ['unspecified'] so can't be specified gettext.translation # codeset default value is ['unspecified'] so can't be specified hmac.new # Stub is a white lie; see comments in the stub diff --git a/tests/stubtest_allowlists/py39.txt b/tests/stubtest_allowlists/py39.txt index 6f951f3f8..76217da78 100644 --- a/tests/stubtest_allowlists/py39.txt +++ b/tests/stubtest_allowlists/py39.txt @@ -40,6 +40,7 @@ distutils.core.extension_keywords distutils.core.gen_usage distutils.core.setup_keywords fractions.Fraction.__new__ # overload is too complicated for stubtest to resolve +functools.cached_property.__set__ # Stub is a while lie; see comments in the stub gettext.install gettext.translation hmac.new # Stub is a white lie; see comments in the stub