1919
2020[2] Python data model, https://docs.python.org/reference/datamodel.html
2121"""
22+ from __future__ import annotations
23+
24+ import typing as ty
25+
26+ InstanceT = ty .TypeVar ('InstanceT' )
27+ T = ty .TypeVar ('T' )
2228
2329from nibabel .deprecated import deprecate_with_version
2430
@@ -96,26 +102,24 @@ class ResetMixin:
96102 10.0
97103 """
98104
99- def reset (self ):
105+ def reset (self ) -> None :
100106 """Reset all OneTimeProperty attributes that may have fired already."""
101- instdict = self .__dict__
102- classdict = self .__class__ .__dict__
103107 # To reset them, we simply remove them from the instance dict. At that
104108 # point, it's as if they had never been computed. On the next access,
105109 # the accessor function from the parent class will be called, simply
106110 # because that's how the python descriptor protocol works.
107- for mname , mval in classdict .items ():
108- if mname in instdict and isinstance (mval , OneTimeProperty ):
111+ for mname , mval in self . __class__ . __dict__ .items ():
112+ if mname in self . __dict__ and isinstance (mval , OneTimeProperty ):
109113 delattr (self , mname )
110114
111115
112- class OneTimeProperty :
116+ class OneTimeProperty ( ty . Generic [ T ]) :
113117 """A descriptor to make special properties that become normal attributes.
114118
115119 This is meant to be used mostly by the auto_attr decorator in this module.
116120 """
117121
118- def __init__ (self , func ):
122+ def __init__ (self , func : ty . Callable [[ InstanceT ], T ] ):
119123 """Create a OneTimeProperty instance.
120124
121125 Parameters
@@ -128,24 +132,35 @@ def __init__(self, func):
128132 """
129133 self .getter = func
130134 self .name = func .__name__
135+ self .__doc__ = func .__doc__
136+
137+ @ty .overload
138+ def __get__ (
139+ self , obj : None , objtype : type [InstanceT ] | None = None
140+ ) -> ty .Callable [[InstanceT ], T ]:
141+ ... # pragma: no cover
142+
143+ @ty .overload
144+ def __get__ (self , obj : InstanceT , objtype : type [InstanceT ] | None = None ) -> T :
145+ ... # pragma: no cover
131146
132- def __get__ (self , obj , type = None ):
147+ def __get__ (
148+ self , obj : InstanceT | None , objtype : type [InstanceT ] | None = None
149+ ) -> T | ty .Callable [[InstanceT ], T ]:
133150 """This will be called on attribute access on the class or instance."""
134151 if obj is None :
135152 # Being called on the class, return the original function. This
136153 # way, introspection works on the class.
137- # return func
138154 return self .getter
139155
140- # Errors in the following line are errors in setting a
141- # OneTimeProperty
156+ # Errors in the following line are errors in setting a OneTimeProperty
142157 val = self .getter (obj )
143158
144- setattr ( obj , self .name , val )
159+ obj . __dict__ [ self .name ] = val
145160 return val
146161
147162
148- def auto_attr (func ) :
163+ def auto_attr (func : ty . Callable [[ InstanceT ], T ]) -> OneTimeProperty [ T ] :
149164 """Decorator to create OneTimeProperty attributes.
150165
151166 Parameters
0 commit comments