Skip to content

Commit a7625c6

Browse files
Adding typehints and overloads for typing properties
1 parent c2e09b8 commit a7625c6

1 file changed

Lines changed: 26 additions & 5 deletions

File tree

src/labthings_fastapi/descriptors/property.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,17 @@
33
"""
44

55
from __future__ import annotations
6-
from typing import TYPE_CHECKING, Annotated, Any, Callable, Optional
6+
from typing import (
7+
TYPE_CHECKING,
8+
Annotated,
9+
Any,
10+
Callable,
11+
Optional,
12+
Generic,
13+
Type,
14+
TypeVar,
15+
overload,
16+
)
717
from weakref import WeakSet
818

919
from typing_extensions import Self
@@ -20,8 +30,11 @@
2030
if TYPE_CHECKING:
2131
from ..thing import Thing
2232

33+
Value = TypeVar("Value")
34+
Descriptor = TypeVar("Descriptor")
2335

24-
class ThingProperty:
36+
37+
class ThingProperty(Generic[Value]):
2538
"""A property that can be accessed via the HTTP API
2639
2740
By default, a ThingProperty is "dumb", i.e. it acts just like
@@ -39,7 +52,7 @@ def __init__(
3952
observable: bool = False,
4053
description: Optional[str] = None,
4154
title: Optional[str] = None,
42-
getter: Optional[Callable] = None,
55+
getter: Optional[Callable[[Thing, Type[Thing]], Value]] = None,
4356
setter: Optional[Callable] = None,
4457
):
4558
if getter and initial_value is not None:
@@ -76,7 +89,15 @@ def description(self):
7689
"""A description of the property"""
7790
return self._description or get_docstring(self._getter, remove_summary=True)
7891

79-
def __get__(self, obj, type=None) -> Any:
92+
@overload
93+
def __get__(self, obj: None, owner: Type[Thing]) -> Descriptor:
94+
"""Called when an attribute is accessed via class not an instance"""
95+
96+
@overload
97+
def __get__(self, obj: Thing, owner: Type[Thing]) -> Value:
98+
"""Called when an attribute is accessed on an instance variable"""
99+
100+
def __get__(self, obj: Optional[Thing], owner: Type[Thing]) -> Value | Descriptor:
80101
"""The value of the property
81102
82103
If `obj` is none (i.e. we are getting the attribute of the class),
@@ -187,7 +208,7 @@ def set_property(body): # We'll annotate body later
187208
description=f"## {self.title}\n\n{self.description or ''}",
188209
)
189210
def get_property():
190-
return self.__get__(thing)
211+
return self.__get__(thing, type(thing))
191212

192213
def property_affordance(
193214
self, thing: Thing, path: Optional[str] = None

0 commit comments

Comments
 (0)