11import requests
2+ from requests .structures import CaseInsensitiveDict
23from dataclasses import dataclass
34from dataclasses_json import dataclass_json , Undefined # type: ignore
45from typing import List , Optional , Dict , Any
@@ -101,40 +102,18 @@ class VolumeMount:
101102@dataclass
102103class Container :
103104 """Container configuration for deployment creation and updates.
104- This class omits the name field which is managed by the system.
105105
106106 :param image: Container image to use
107107 :param exposed_port: Port to expose from the container
108+ :param name: Name of the container (system-managed, read-only)
108109 :param healthcheck: Optional health check configuration
109110 :param entrypoint_overrides: Optional entrypoint override settings
110111 :param env: Optional list of environment variables
111112 :param volume_mounts: Optional list of volume mounts
112113 """
113114 image : str
114115 exposed_port : int
115- healthcheck : Optional [HealthcheckSettings ] = None
116- entrypoint_overrides : Optional [EntrypointOverridesSettings ] = None
117- env : Optional [List [EnvVar ]] = None
118- volume_mounts : Optional [List [VolumeMount ]] = None
119-
120-
121- @dataclass_json
122- @dataclass
123- class ContainerInfo :
124- """Container configuration for deployments.
125- This class is read-only and includes the system-managed name field.
126-
127- :param name: Name of the container (system-managed)
128- :param image: Container image to use
129- :param exposed_port: Port to expose from the container
130- :param healthcheck: Optional health check configuration
131- :param entrypoint_overrides: Optional entrypoint override settings
132- :param env: Optional list of environment variables
133- :param volume_mounts: Optional list of volume mounts
134- """
135- name : str
136- image : str
137- exposed_port : int
116+ name : Optional [str ] = None
138117 healthcheck : Optional [HealthcheckSettings ] = None
139118 entrypoint_overrides : Optional [EntrypointOverridesSettings ] = None
140119 env : Optional [List [EnvVar ]] = None
@@ -250,7 +229,6 @@ class ScalingOptions:
250229@dataclass
251230class Deployment :
252231 """Configuration for creating or updating a container deployment.
253- This class uses Container instead of ContainerInfo to prevent name setting.
254232
255233 :param name: Name of the deployment
256234 :param container_registry_settings: Settings for accessing container registry
@@ -264,14 +242,27 @@ class Deployment:
264242 """
265243 name : str
266244 container_registry_settings : ContainerRegistrySettings
267- containers : List [Container ] | List [ ContainerInfo ]
245+ containers : List [Container ]
268246 compute : ComputeResource
269247 is_spot : bool = False
270248 endpoint_base_url : Optional [str ] = None
271249 scaling : Optional [ScalingOptions ] = None
272250 created_at : Optional [str ] = None
273251
274- inference_key : Optional [str ] = None
252+ _inference_key : Optional [str ] = None
253+
254+ def __str__ (self ):
255+ """String representation of the deployment, excluding sensitive information."""
256+ # Get all attributes except _inference_key
257+ attrs = {k : v for k , v in self .__dict__ .items () if k !=
258+ '_inference_key' }
259+ # Format each attribute
260+ attr_strs = [f"{ k } ={ repr (v )} " for k , v in attrs .items ()]
261+ return f"Deployment({ ', ' .join (attr_strs )} )"
262+
263+ def __repr__ (self ):
264+ """Repr representation of the deployment, excluding sensitive information."""
265+ return self .__str__ ()
275266
276267 @classmethod
277268 def from_dict_with_inference_key (cls , data : Dict [str , Any ], inference_key : str = None , ** kwargs ) -> 'Deployment' :
@@ -282,22 +273,51 @@ def from_dict_with_inference_key(cls, data: Dict[str, Any], inference_key: str =
282273 :param **kwargs: Additional arguments to pass to from_dict
283274 :return: Deployment instance
284275 """
285- deployment = cls .from_dict (data , ** kwargs )
276+ deployment = Deployment .from_dict (data , infer_missing = True )
286277 deployment ._inference_key = inference_key
287278 return deployment
288279
289280 def run_sync (self , data : Dict [str , Any ], path : str = "" , timeout_seconds : int = 60 * 5 ):
290281 if self ._inference_key is None :
291- raise ValueError ("Inference key is not set" ) # TODO: review this
282+ # TODO: do something better
283+ raise ValueError ("Inference key is not set" )
292284
293- # TODO: create a request object
294- return requests .post (
285+ response = requests .post (
295286 url = f"{ self .endpoint_base_url } { path } " ,
296287 json = data ,
297288 headers = {"Authorization" : f"Bearer { self ._inference_key } " },
298289 timeout = timeout_seconds
299290 )
300291
292+ return InferenceResponse (
293+ body = response .json (),
294+ headers = response .headers ,
295+ status_code = response .status_code ,
296+ status_text = response .reason
297+ )
298+
299+ def health (self ):
300+ healthcheck_path = "health"
301+ if self .containers and self .containers [0 ].healthcheck and self .containers [0 ].healthcheck .path :
302+ healthcheck_path = self .containers [0 ].healthcheck .path .lstrip ('/' )
303+
304+ response = requests .get (
305+ url = f"{ self .endpoint_base_url } { healthcheck_path } " ,
306+ headers = {"Authorization" : f"Bearer { self ._inference_key } " },
307+ )
308+ return response # TODO: agree on response format
309+ # Function alias
310+ healthcheck = health
311+
312+
313+ @dataclass_json (undefined = Undefined .EXCLUDE )
314+ @dataclass
315+ class InferenceResponse :
316+ body : Any
317+ headers : CaseInsensitiveDict [str ]
318+ status_code : int
319+ status_text : str
320+
301321
302322@dataclass_json
303323@dataclass
@@ -421,7 +441,7 @@ def get_deployments(self) -> List[Deployment]:
421441 :rtype: List[Deployment]
422442 """
423443 response = self .client .get (CONTAINER_DEPLOYMENTS_ENDPOINT )
424- return [Deployment .from_dict (deployment , infer_missing = True ) for deployment in response .json ()]
444+ return [Deployment .from_dict_with_inference_key (deployment , self . _inference_key ) for deployment in response .json ()]
425445
426446 def get_deployment_by_name (self , deployment_name : str ) -> Deployment :
427447 """Get a deployment by name
@@ -453,7 +473,7 @@ def create_deployment(
453473 CONTAINER_DEPLOYMENTS_ENDPOINT ,
454474 deployment .to_dict ()
455475 )
456- return Deployment .from_dict (response .json (), infer_missing = True )
476+ return Deployment .from_dict_with_inference_key (response .json (), self . _inference_key )
457477
458478 def update_deployment (self , deployment_name : str , deployment : Deployment ) -> Deployment :
459479 """Update an existing deployment
@@ -469,7 +489,7 @@ def update_deployment(self, deployment_name: str, deployment: Deployment) -> Dep
469489 f"{ CONTAINER_DEPLOYMENTS_ENDPOINT } /{ deployment_name } " ,
470490 deployment .to_dict ()
471491 )
472- return Deployment .from_dict (response .json (), infer_missing = True )
492+ return Deployment .from_dict_with_inference_key (response .json (), self . _inference_key )
473493
474494 def delete_deployment (self , deployment_name : str ) -> None :
475495 """Delete a deployment
0 commit comments