1from __future__ import annotations
2
3from typing import (
4 Any,
5 Callable,
6 Generic,
7 Optional,
8 Type,
9 TypeVar,
10)
11
12from typing_extensions import (
13 Concatenate,
14 ParamSpec,
15 Self,
16)
17
18
19SelfT = TypeVar("SelfT")
20P = ParamSpec("P")
21HybridT = TypeVar("HybridT", covariant=True)
22
23
24class hybridmethod(Generic[SelfT, P, HybridT]):
25 def __init__(
26 self,
27 func: Callable[
28 Concatenate[type[SelfT], P], HybridT
29 ], # Must be the classmethod version
30 ):
31 self.cls_func = func
32 self.__doc__ = func.__doc__
33
34 def instancemethod(self, func: Callable[Concatenate[SelfT, P], HybridT]) -> Self:
35 self.instance_func = func
36 return self
37
38 def __get__(
39 self, instance: Optional[SelfT], owner: Type[SelfT]
40 ) -> Callable[P, HybridT]:
41 if instance is None or self.instance_func is None:
42 # either bound to the class, or no instance method available
43 return self.cls_func.__get__(owner, None)
44 return self.instance_func.__get__(instance, owner)
45
46
47T_co = TypeVar("T_co")
48TT_co = TypeVar("TT_co", bound="type[Any]")
49
50
51class classproperty(Generic[TT_co, T_co]):
52 def __init__(self, func: Callable[[TT_co], T_co]):
53 self.__func__ = func
54
55 def __get__(self, instance: Any, type: TT_co) -> T_co:
56 return self.__func__(type)