"""Utility functions for the API."""fromcollections.abcimportCallablefromfunctoolsimportlru_cache,wrapsfromtypingimportAny,TypeVar,castimporthttpxfrompydanticimportBaseModelfrompoiesis.api.constantsimportget_poiesis_api_constantsfrompoiesis.api.exceptionsimportInternalServerExceptionfrompoiesis.api.tes.modelsimportTesTaskT=TypeVar("T")
[docs]defpydantic_to_dict_response(func:Callable[...,Any])->Callable[...,Any]:"""Decorator that converts a Pydantic model return value to a dict. This decorator is useful for API endpoints that return Pydantic models, automatically converting the model to a dictionary using the model_dump method. Args: func: The function to decorate. Returns: A wrapped function that converts Pydantic model returns to dictionaries. Example: ```python from pydantic import BaseModel class User(BaseModel): name: str age: int @pydantic_to_dict_response def get_user() -> User: return User(name="John", age=30) # When called, get_user() will return a dict: {"name": "John", "age": 30} ``` """@wraps(func)asyncdefwrapper(*args:Any,**kwargs:Any)->Any:result=awaitfunc(*args,**kwargs)ifisinstance(result,BaseModel):returnresult.model_dump(mode="json",exclude_none=True)returnresultreturncast(Callable[...,Any],wrapper)
[docs]deftask_to_minimal_task(task:TesTask)->TesTask:"""Convert a task to a minimal task. Note: The TES specification says that the task should only return the id, state. However, the openAPI spec has the executors as required fields, so we need to return a minimal task. """returnTesTask(id=task.id,state=task.state,executors=task.executors,)
[docs]deftask_to_basic_task(task:TesTask)->TesTask:"""Convert a task to a basic task. Task message will include all fields EXCEPT: - tesTask.ExecutorLog.stdout - tesTask.ExecutorLog.stderr - tesInput.content - tesTaskLog.system_logs """iftask.logs:forlogintask.logs:iflog.logs:forlogsinlog.logs:logs.stdout=Nonelogs.stderr=Nonelog.system_logs=Noneiftask.inputs:forinputintask.inputs:input.content=Nonereturntask
[docs]@lru_cachedefget_oidc_introspect_url()->str:"""Get the OIDC introspect URL. Returns: str: The OIDC introspect URL. """discovery_url=get_poiesis_api_constants().Auth.OIDC.DISCOVERY_URLtry:withhttpx.Client()asclient:resp=client.get(discovery_url,timeout=10)resp.raise_for_status()metadata=resp.json()ifintrospect_url:=metadata.get("introspection_endpoint"):returncast(str,introspect_url)else:raiseInternalServerException("OIDC discovery document does not contain 'introspection_endpoint'.")exceptExceptionase:raiseInternalServerException(f"Failed to fetch OIDC introspect URL: {e}")frome
[docs]@lru_cachedefget_oidc_jwks_uri()->str:"""Get the OIDC JWKS URI from the discovery document."""discovery_url=get_poiesis_api_constants().Auth.OIDC.DISCOVERY_URLtry:withhttpx.Client()asclient:resp=client.get(discovery_url,timeout=10)resp.raise_for_status()metadata=resp.json()ifjwks_uri:=metadata.get("jwks_uri"):returncast(str,jwks_uri)else:raiseInternalServerException("OIDC discovery document does not contain 'jwks_uri'.")exceptExceptionase:raiseInternalServerException(f"Failed to fetch OIDC JWKS URI: {e}")frome