summaryrefslogtreecommitdiffstats
path: root/src/aristaproto/utils.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/aristaproto/utils.py')
-rw-r--r--src/aristaproto/utils.py56
1 files changed, 56 insertions, 0 deletions
diff --git a/src/aristaproto/utils.py b/src/aristaproto/utils.py
new file mode 100644
index 0000000..b977fc7
--- /dev/null
+++ b/src/aristaproto/utils.py
@@ -0,0 +1,56 @@
+from __future__ import annotations
+
+from typing import (
+ Any,
+ Callable,
+ Generic,
+ Optional,
+ Type,
+ TypeVar,
+)
+
+from typing_extensions import (
+ Concatenate,
+ ParamSpec,
+ Self,
+)
+
+
+SelfT = TypeVar("SelfT")
+P = ParamSpec("P")
+HybridT = TypeVar("HybridT", covariant=True)
+
+
+class hybridmethod(Generic[SelfT, P, HybridT]):
+ def __init__(
+ self,
+ func: Callable[
+ Concatenate[type[SelfT], P], HybridT
+ ], # Must be the classmethod version
+ ):
+ self.cls_func = func
+ self.__doc__ = func.__doc__
+
+ def instancemethod(self, func: Callable[Concatenate[SelfT, P], HybridT]) -> Self:
+ self.instance_func = func
+ return self
+
+ def __get__(
+ self, instance: Optional[SelfT], owner: Type[SelfT]
+ ) -> Callable[P, HybridT]:
+ if instance is None or self.instance_func is None:
+ # either bound to the class, or no instance method available
+ return self.cls_func.__get__(owner, None)
+ return self.instance_func.__get__(instance, owner)
+
+
+T_co = TypeVar("T_co")
+TT_co = TypeVar("TT_co", bound="type[Any]")
+
+
+class classproperty(Generic[TT_co, T_co]):
+ def __init__(self, func: Callable[[TT_co], T_co]):
+ self.__func__ = func
+
+ def __get__(self, instance: Any, type: TT_co) -> T_co:
+ return self.__func__(type)