3
3
import posixpath
4
4
import warnings
5
5
from abc import ABC
6
- from typing import ItemsView , cast
6
+ from typing import ItemsView , Type , cast
7
7
8
8
from typing_extensions import (
9
9
TYPE_CHECKING ,
@@ -92,49 +92,50 @@ def update(self, **attributes): # type: ignore[reportIncompatibleMethodOverride
92
92
super ().update (** result )
93
93
94
94
95
- T = TypeVar ("T" , bound = Resource )
95
+ _T = TypeVar ("_T" , bound = Resource )
96
+ _T_co = TypeVar ("_T_co" , bound = Resource , covariant = True )
96
97
97
98
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 : ...
100
101
101
102
102
- class ResourceSequence (Protocol [T ]):
103
+ class ResourceSequence (Protocol [_T ]):
103
104
@overload
104
- def __getitem__ (self , index : SupportsIndex , / ) -> T : ...
105
+ def __getitem__ (self , index : SupportsIndex , / ) -> _T : ...
105
106
106
107
@overload
107
- def __getitem__ (self , index : slice , / ) -> List [T ]: ...
108
+ def __getitem__ (self , index : slice , / ) -> List [_T ]: ...
108
109
109
110
def __len__ (self ) -> int : ...
110
111
111
- def __iter__ (self ) -> Iterator [T ]: ...
112
+ def __iter__ (self ) -> Iterator [_T ]: ...
112
113
113
114
def __str__ (self ) -> str : ...
114
115
115
116
def __repr__ (self ) -> str : ...
116
117
117
118
118
- class _ResourceSequence (Sequence [T ], ResourceSequence [T ]):
119
+ class _ResourceSequence (Sequence [_T ], ResourceSequence [_T ]):
119
120
def __init__ (
120
121
self ,
121
122
ctx : Context ,
122
123
path : str ,
123
- factory : ResourceFactory = _Resource ,
124
+ factory : ResourceFactory [ _T ] | None = None ,
124
125
uid : str = "guid" ,
125
126
):
126
127
self ._ctx = ctx
127
128
self ._path = path
128
129
self ._uid = uid
129
- self ._factory = factory
130
+ self ._factory = factory or cast ( ResourceFactory [ _T ], _Resource )
130
131
131
132
def __getitem__ (self , index ):
132
133
return list (self .fetch ())[index ]
133
134
134
135
def __len__ (self ) -> int :
135
136
return len (list (self .fetch ()))
136
137
137
- def __iter__ (self ) -> Iterator [T ]:
138
+ def __iter__ (self ) -> Iterator [_T ]:
138
139
return iter (self .fetch ())
139
140
140
141
def __str__ (self ) -> str :
@@ -143,32 +144,34 @@ def __str__(self) -> str:
143
144
def __repr__ (self ) -> str :
144
145
return repr (self .fetch ())
145
146
146
- def create (self , ** attributes : Any ) -> T :
147
+ def create (self , ** attributes : Any ) -> _T :
147
148
response = self ._ctx .client .post (self ._path , json = attributes )
148
149
result = response .json ()
149
150
uid = result [self ._uid ]
150
151
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
152
154
153
- def fetch (self , ** conditions ) -> Iterable [T ]:
155
+ def fetch (self , ** conditions : Any ) -> Iterable [_T ]:
154
156
response = self ._ctx .client .get (self ._path , params = conditions )
155
157
results = response .json ()
156
- resources : List [T ] = []
158
+ resources : List [_T ] = []
157
159
for result in results :
158
160
uid = result [self ._uid ]
159
161
path = posixpath .join (self ._path , uid )
160
- resource = cast ( T , self ._factory (self ._ctx , path , ** result ) )
162
+ resource = self ._factory (self ._ctx , path , ** result )
161
163
resources .append (resource )
162
164
163
165
return resources
164
166
165
- def find (self , * args : str ) -> T :
167
+ def find (self , * args : str ) -> _T :
166
168
path = posixpath .join (self ._path , * args )
167
169
response = self ._ctx .client .get (path )
168
170
result = response .json ()
169
- return cast (T , self ._factory (self ._ctx , path , ** result ))
171
+ resource = self ._factory (self ._ctx , path , ** result )
172
+ return resource
170
173
171
- def find_by (self , ** conditions ) -> T | None :
174
+ def find_by (self , ** conditions : Any ) -> _T | None :
172
175
"""
173
176
Find the first record matching the specified conditions.
174
177
@@ -183,19 +186,20 @@ def find_by(self, **conditions) -> T | None:
183
186
Optional[T]
184
187
The first record matching the conditions, or `None` if no match is found.
185
188
"""
186
- collection : Iterable [ T ] = self .fetch (** conditions )
189
+ collection = self .fetch (** conditions )
187
190
return next ((v for v in collection if v .items () >= conditions .items ()), None )
188
191
189
192
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 ]:
192
195
paginator = Paginator (self ._ctx , self ._path , dict (** conditions ))
193
196
for page in paginator .fetch_pages ():
194
197
resources = []
195
198
results = page .results
196
199
for result in results :
197
200
uid = result [self ._uid ]
198
201
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
+
200
204
resources .append (resource )
201
205
yield from resources
0 commit comments