33"""
44
55from __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+ )
717from weakref import WeakSet
818
919from typing_extensions import Self
2030if 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