33import posixpath
44import warnings
55from abc import ABC
6- from typing import ItemsView , cast
6+ from typing import ItemsView , Type , cast
77
88from typing_extensions import (
99 TYPE_CHECKING ,
@@ -92,49 +92,50 @@ def update(self, **attributes): # type: ignore[reportIncompatibleMethodOverride
9292 super ().update (** result )
9393
9494
95- T = TypeVar ("T" , bound = Resource )
95+ _T = TypeVar ("_T" , bound = Resource )
96+ _T_co = TypeVar ("_T_co" , bound = Resource , covariant = True )
9697
9798
98- class ResourceFactory (Protocol ):
99- def __call__ (self , ctx : Context , path : str , ** attributes ) -> Resource : ...
99+ class ResourceFactory (Protocol [ _T_co ] ):
100+ def __call__ (self , ctx : Context , path : str , ** attributes : Any ) -> _T_co : ...
100101
101102
102- class ResourceSequence (Protocol [T ]):
103+ class ResourceSequence (Protocol [_T ]):
103104 @overload
104- def __getitem__ (self , index : SupportsIndex , / ) -> T : ...
105+ def __getitem__ (self , index : SupportsIndex , / ) -> _T : ...
105106
106107 @overload
107- def __getitem__ (self , index : slice , / ) -> List [T ]: ...
108+ def __getitem__ (self , index : slice , / ) -> List [_T ]: ...
108109
109110 def __len__ (self ) -> int : ...
110111
111- def __iter__ (self ) -> Iterator [T ]: ...
112+ def __iter__ (self ) -> Iterator [_T ]: ...
112113
113114 def __str__ (self ) -> str : ...
114115
115116 def __repr__ (self ) -> str : ...
116117
117118
118- class _ResourceSequence (Sequence [T ], ResourceSequence [T ]):
119+ class _ResourceSequence (Sequence [_T ], ResourceSequence [_T ]):
119120 def __init__ (
120121 self ,
121122 ctx : Context ,
122123 path : str ,
123- factory : ResourceFactory = _Resource ,
124+ factory : ResourceFactory [ _T ] | None = None ,
124125 uid : str = "guid" ,
125126 ):
126127 self ._ctx = ctx
127128 self ._path = path
128129 self ._uid = uid
129- self ._factory = factory
130+ self ._factory = factory or cast ( ResourceFactory [ _T ], _Resource )
130131
131132 def __getitem__ (self , index ):
132133 return list (self .fetch ())[index ]
133134
134135 def __len__ (self ) -> int :
135136 return len (list (self .fetch ()))
136137
137- def __iter__ (self ) -> Iterator [T ]:
138+ def __iter__ (self ) -> Iterator [_T ]:
138139 return iter (self .fetch ())
139140
140141 def __str__ (self ) -> str :
@@ -143,32 +144,34 @@ def __str__(self) -> str:
143144 def __repr__ (self ) -> str :
144145 return repr (self .fetch ())
145146
146- def create (self , ** attributes : Any ) -> T :
147+ def create (self , ** attributes : Any ) -> _T :
147148 response = self ._ctx .client .post (self ._path , json = attributes )
148149 result = response .json ()
149150 uid = result [self ._uid ]
150151 path = posixpath .join (self ._path , uid )
151- return cast (T , self ._factory (self ._ctx , path , ** result ))
152+ resource = self ._factory (self ._ctx , path , ** result )
153+ return resource
152154
153- def fetch (self , ** conditions ) -> Iterable [T ]:
155+ def fetch (self , ** conditions : Any ) -> Iterable [_T ]:
154156 response = self ._ctx .client .get (self ._path , params = conditions )
155157 results = response .json ()
156- resources : List [T ] = []
158+ resources : List [_T ] = []
157159 for result in results :
158160 uid = result [self ._uid ]
159161 path = posixpath .join (self ._path , uid )
160- resource = cast ( T , self ._factory (self ._ctx , path , ** result ) )
162+ resource = self ._factory (self ._ctx , path , ** result )
161163 resources .append (resource )
162164
163165 return resources
164166
165- def find (self , * args : str ) -> T :
167+ def find (self , * args : str ) -> _T :
166168 path = posixpath .join (self ._path , * args )
167169 response = self ._ctx .client .get (path )
168170 result = response .json ()
169- return cast (T , self ._factory (self ._ctx , path , ** result ))
171+ resource = self ._factory (self ._ctx , path , ** result )
172+ return resource
170173
171- def find_by (self , ** conditions ) -> T | None :
174+ def find_by (self , ** conditions : Any ) -> _T | None :
172175 """
173176 Find the first record matching the specified conditions.
174177
@@ -183,19 +186,20 @@ def find_by(self, **conditions) -> T | None:
183186 Optional[T]
184187 The first record matching the conditions, or `None` if no match is found.
185188 """
186- collection : Iterable [ T ] = self .fetch (** conditions )
189+ collection = self .fetch (** conditions )
187190 return next ((v for v in collection if v .items () >= conditions .items ()), None )
188191
189192
190- class _PaginatedResourceSequence (_ResourceSequence [T ]):
191- def fetch (self , ** conditions ) -> Iterator [ T ]:
193+ class _PaginatedResourceSequence (_ResourceSequence [_T ]):
194+ def fetch (self , ** conditions : Any ) -> Iterable [ _T ]:
192195 paginator = Paginator (self ._ctx , self ._path , dict (** conditions ))
193196 for page in paginator .fetch_pages ():
194197 resources = []
195198 results = page .results
196199 for result in results :
197200 uid = result [self ._uid ]
198201 path = posixpath .join (self ._path , uid )
199- resource = cast (T , self ._factory (self ._ctx , path , ** result ))
202+ resource = self ._factory (self ._ctx , path , ** result )
203+
200204 resources .append (resource )
201205 yield from resources
0 commit comments