|
1 | 1 | from __future__ import annotations
|
2 | 2 |
|
3 |
| -from typing import TYPE_CHECKING, Any, Union, TypeVar, cast |
| 3 | +from typing import TYPE_CHECKING, Any, Union, Generic, TypeVar, Callable, cast, overload |
4 | 4 | from datetime import date, datetime
|
| 5 | +from typing_extensions import Self |
5 | 6 |
|
6 | 7 | import pydantic
|
7 | 8 | from pydantic.fields import FieldInfo
|
8 | 9 |
|
9 | 10 | from ._types import StrBytesIntFloat
|
10 | 11 |
|
| 12 | +_T = TypeVar("_T") |
11 | 13 | _ModelT = TypeVar("_ModelT", bound=pydantic.BaseModel)
|
12 | 14 |
|
13 | 15 | # --------------- Pydantic v2 compatibility ---------------
|
@@ -178,8 +180,43 @@ class GenericModel(pydantic.generics.GenericModel, pydantic.BaseModel):
|
178 | 180 | # cached properties
|
179 | 181 | if TYPE_CHECKING:
|
180 | 182 | cached_property = property
|
| 183 | + |
| 184 | + # we define a separate type (copied from typeshed) |
| 185 | + # that represents that `cached_property` is `set`able |
| 186 | + # at runtime, which differs from `@property`. |
| 187 | + # |
| 188 | + # this is a separate type as editors likely special case |
| 189 | + # `@property` and we don't want to cause issues just to have |
| 190 | + # more helpful internal types. |
| 191 | + |
| 192 | + class typed_cached_property(Generic[_T]): |
| 193 | + func: Callable[[Any], _T] |
| 194 | + attrname: str | None |
| 195 | + |
| 196 | + def __init__(self, func: Callable[[Any], _T]) -> None: |
| 197 | + ... |
| 198 | + |
| 199 | + @overload |
| 200 | + def __get__(self, instance: None, owner: type[Any] | None = None) -> Self: |
| 201 | + ... |
| 202 | + |
| 203 | + @overload |
| 204 | + def __get__(self, instance: object, owner: type[Any] | None = None) -> _T: |
| 205 | + ... |
| 206 | + |
| 207 | + def __get__(self, instance: object, owner: type[Any] | None = None) -> _T | Self: |
| 208 | + raise NotImplementedError() |
| 209 | + |
| 210 | + def __set_name__(self, owner: type[Any], name: str) -> None: |
| 211 | + ... |
| 212 | + |
| 213 | + # __set__ is not defined at runtime, but @cached_property is designed to be settable |
| 214 | + def __set__(self, instance: object, value: _T) -> None: |
| 215 | + ... |
181 | 216 | else:
|
182 | 217 | try:
|
183 | 218 | from functools import cached_property as cached_property
|
184 | 219 | except ImportError:
|
185 | 220 | from cached_property import cached_property as cached_property
|
| 221 | + |
| 222 | + typed_cached_property = cached_property |
0 commit comments