11import functools
22from collections .abc import Callable
33from json import JSONDecodeError
4- from typing import Any , TypeVar , TYPE_CHECKING , Type
4+ from typing import Any , TypeVar , TYPE_CHECKING , Type , Generic
55from urllib .parse import quote , urlparse
66
77from requests import Response
@@ -111,30 +111,42 @@ def __init__(self, *guids: str):
111111 self .guids = list (guids )
112112
113113
114- ENTITY_TYPE = TypeVar ("ENTITY_TYPE" , bound = Entity )
114+ ENTITY_TYPE = TypeVar ("ENTITY_TYPE" , bound = Entity , covariant = True )
115115
116116
117- class EntityManager (object ):
118- def __init__ (self , target_endpoint : str , client : "CloudFoundryClient" , entity_uri : str , entity_type : ENTITY_TYPE = Entity ):
117+ class EntityManager (Generic [ENTITY_TYPE ]):
118+ def __init__ (
119+ self ,
120+ target_endpoint : str ,
121+ client : "CloudFoundryClient" ,
122+ entity_uri : str ,
123+ entity_type : type [ENTITY_TYPE ] = Entity
124+ ):
119125 self .target_endpoint = target_endpoint
120126 self .entity_uri = entity_uri
121127 self .client = client
122128 self .entity_type = entity_type
123129
124- def _post (self , url : str , data : dict | None = None , files : Any = None , entity_type : ENTITY_TYPE = None ) -> Entity :
125- response = self .client .post (url , json = data , files = files )
126- return self ._read_response (response , entity_type )
127-
128- def _get (self , url : str , entity_type : ENTITY_TYPE | None = None , ** kwargs ) -> Entity :
130+ def _get (self , url : str , entity_type : type [ENTITY_TYPE ] | None = None , ** kwargs ) -> ENTITY_TYPE :
129131 url_requested = EntityManager ._get_url_with_encoded_params (url , ** kwargs )
130132 response = self .client .get (url_requested )
131133 return self ._read_response (response , entity_type )
132134
133- def _put (self , url : str , data : dict , entity_type : ENTITY_TYPE | None = None ) -> Entity :
135+ def _post (
136+ self ,
137+ url : str ,
138+ data : dict | None = None ,
139+ entity_type : type [ENTITY_TYPE ] | None = None ,
140+ files : Any = None
141+ ) -> ENTITY_TYPE :
142+ response = self .client .post (url , json = data , files = files )
143+ return self ._read_response (response , entity_type )
144+
145+ def _put (self , url : str , data : dict , entity_type : type [ENTITY_TYPE ] | None = None ) -> ENTITY_TYPE :
134146 response = self .client .put (url , json = data )
135147 return self ._read_response (response , entity_type )
136148
137- def _patch (self , url : str , data : dict , entity_type : ENTITY_TYPE | None = None ) -> Entity :
149+ def _patch (self , url : str , data : dict , entity_type : type [ ENTITY_TYPE ] | None = None ) -> ENTITY_TYPE :
138150 response = self .client .patch (url , json = data )
139151 return self ._read_response (response , entity_type )
140152
@@ -166,21 +178,21 @@ def _extract_job_guid(job_location):
166178 job_guid = job_url .path .rsplit ("/" , 1 )[- 1 ]
167179 return job_guid
168180
169- def _list (self , requested_path : str , entity_type : ENTITY_TYPE | None = None , ** kwargs ) -> Pagination [Entity ]:
181+ def _list (self , requested_path : str , entity_type : type [ ENTITY_TYPE ] | None = None , ** kwargs ) -> Pagination [ENTITY_TYPE ]:
170182 url_requested = EntityManager ._get_url_with_encoded_params ("%s%s" % (self .target_endpoint , requested_path ), ** kwargs )
171183 response_json = self ._read_response (self .client .get (url_requested ), JsonObject )
172184 return self ._pagination (response_json , entity_type )
173185
174- def _attempt_to_paginate (self , url_requested : str , entity_type : ENTITY_TYPE | None = None ) \
175- -> Pagination [Entity ] | Entity :
186+ def _attempt_to_paginate (self , url_requested : str , entity_type : type [ ENTITY_TYPE ] | None = None ) \
187+ -> Pagination [ENTITY_TYPE ] | ENTITY_TYPE :
176188 response_json = self ._read_response (self .client .get (url_requested ), JsonObject )
177189 if "resources" in response_json :
178190 return self ._pagination (response_json , entity_type )
179191 else :
180192 return response_json
181193
182- def _pagination (self , page : JsonObject , entity_type : ENTITY_TYPE | None = None ) -> Pagination [Entity ]:
183- def _entity (json_object : JsonObject ) -> Entity :
194+ def _pagination (self , page : JsonObject , entity_type : type [ ENTITY_TYPE ] | None = None ) -> Pagination [ENTITY_TYPE ]:
195+ def _entity (json_object : JsonObject ) -> ENTITY_TYPE :
184196 return self ._entity (json_object , entity_type )
185197
186198 return Pagination (page ,
@@ -200,54 +212,58 @@ def _next_page(self, current_page: JsonObject) -> JsonObject | None:
200212 return None
201213 return self ._read_response (self .client .get (current_page ["pagination" ]["next" ]["href" ]), JsonObject )
202214
203- def _create (self , data : dict ) -> Entity :
215+ def _create (self , data : dict ) -> ENTITY_TYPE :
204216 url = "%s%s" % (self .target_endpoint , self .entity_uri )
205217 return self ._post (url , data = data )
206218
207- def _upload_bits (self , resource_id : str , filename : str ) -> Entity :
219+ def _upload_bits (self , resource_id : str , filename : str ) -> ENTITY_TYPE :
208220 url = "%s%s/%s/upload" % (self .target_endpoint , self .entity_uri , resource_id )
209221 files = {"bits" : (filename , open (filename , "rb" ))}
210222 return self ._post (url , files = files )
211223
212- def _update (self , resource_id : str , data : dict ) -> Entity :
224+ def _update (self , resource_id : str , data : dict ) -> ENTITY_TYPE :
213225 url = "%s%s/%s" % (self .target_endpoint , self .entity_uri , resource_id )
214226 return self ._patch (url , data )
215227
216- def __iter__ (self ) -> Pagination [Entity ]:
228+ def __iter__ (self ) -> Pagination [ENTITY_TYPE ]:
217229 return self .list ()
218230
219- def __getitem__ (self , entity_guid ) -> Entity :
231+ def __getitem__ (self , entity_guid ) -> ENTITY_TYPE :
220232 return self .get (entity_guid )
221233
222234 def __len__ (self ):
223235 return self .len ()
224236
225237 def len (self , ** kwargs ):
226238 url_requested = EntityManager ._get_url_with_encoded_params ("%s%s" % (self .target_endpoint , self .entity_uri ), ** kwargs )
227- response_json = self ._read_response (self .client .get (url_requested , JsonObject ) )
239+ response_json = self ._read_response (self .client .get (url_requested ) , JsonObject )
228240 pagination = response_json .get ("pagination" )
229241 if pagination is not None :
230242 return pagination .get ("total_results" , 0 )
231243 else :
232244 return 0
233245
234- def list (self , ** kwargs ) -> Pagination [Entity ]:
246+ def list (self , ** kwargs ) -> Pagination [ENTITY_TYPE ]:
235247 return self ._list (self .entity_uri , ** kwargs )
236248
237- def get_first (self , ** kwargs ) -> Entity | None :
249+ def get_first (self , ** kwargs ) -> ENTITY_TYPE | None :
238250 kwargs .setdefault ("per_page" , 1 )
239251 for entity in self ._list (self .entity_uri , ** kwargs ):
240252 return entity
241253 return None
242254
243- def get (self , entity_id : str , * extra_paths , ** kwargs ) -> Entity :
255+ def get (self , entity_id : str , * extra_paths , ** kwargs ) -> ENTITY_TYPE :
244256 if len (extra_paths ) == 0 :
245257 requested_path = "%s%s/%s" % (self .target_endpoint , self .entity_uri , entity_id )
246258 else :
247259 requested_path = "%s%s/%s/%s" % (self .target_endpoint , self .entity_uri , entity_id , "/" .join (extra_paths ))
248260 return self ._get (requested_path , ** kwargs )
249261
250- def _read_response (self , response : Response , entity_type : ENTITY_TYPE | None ) -> JsonObject | Entity :
262+ def _read_response (
263+ self ,
264+ response : Response ,
265+ entity_type : type [ENTITY_TYPE ] | type [JsonObject ] | None
266+ ) -> JsonObject | ENTITY_TYPE :
251267 try :
252268 result = response .json (object_pairs_hook = JsonObject )
253269 except JSONDecodeError :
@@ -289,7 +305,7 @@ def _include_resources(self, resource: JsonObject, result: JsonObject) -> None:
289305 def _get_entity_type (entity_name : str ) -> Type [ENTITY_TYPE ]:
290306 return Entity
291307
292- def _entity (self , result : JsonObject , entity_type : ENTITY_TYPE | None ) -> JsonObject | Entity :
308+ def _entity (self , result : JsonObject , entity_type : type [ ENTITY_TYPE ] | None ) -> JsonObject | ENTITY_TYPE :
293309 if "guid" in result or ("links" in result and "job" in result ["links" ]):
294310 return (entity_type or self .entity_type )(self .target_endpoint , self .client , ** result )
295311 else :
@@ -301,7 +317,7 @@ def _append_encoded_parameter(parameters: list[str], args: tuple[str, Any]) -> l
301317 parameter_name , parameter_value = args [0 ], args [1 ]
302318 if isinstance (parameter_value , (list , tuple )):
303319 parameters .append ("%s=%s" % (parameter_name , quote ("," .join (parameter_value ))))
304- elif isinstance (parameter_value , ( dict ) ) and parameter_name == "fields" :
320+ elif isinstance (parameter_value , dict ) and parameter_name == "fields" :
305321 for resource , key in parameter_value .items ():
306322 parameters .append ("%s[%s]=%s" % (parameter_name , resource , "," .join (key )))
307323 else :
0 commit comments