codeapi-client 0.4.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- codeapi/__init__.py +17 -0
- codeapi/client/__init__.py +37 -0
- codeapi/client/_async/__init__.py +357 -0
- codeapi/client/_async/_app.py +369 -0
- codeapi/client/_async/_cli.py +334 -0
- codeapi/client/_async/_code.py +211 -0
- codeapi/client/_async/_jobs.py +512 -0
- codeapi/client/_async/_mcp.py +445 -0
- codeapi/client/_async/_web.py +343 -0
- codeapi/client/_base.py +118 -0
- codeapi/client/_sync/__init__.py +347 -0
- codeapi/client/_sync/_app.py +367 -0
- codeapi/client/_sync/_cli.py +332 -0
- codeapi/client/_sync/_code.py +203 -0
- codeapi/client/_sync/_jobs.py +497 -0
- codeapi/client/_sync/_mcp.py +442 -0
- codeapi/client/_sync/_web.py +341 -0
- codeapi/client/_utils.py +61 -0
- codeapi/client/py.typed +0 -0
- codeapi/types/__init__.py +77 -0
- codeapi/types/_api.py +30 -0
- codeapi/types/_base.py +21 -0
- codeapi/types/_code.py +31 -0
- codeapi/types/_enums.py +150 -0
- codeapi/types/_env.py +65 -0
- codeapi/types/_exc.py +35 -0
- codeapi/types/_job.py +67 -0
- codeapi/types/_json.py +67 -0
- codeapi/types/_stream.py +36 -0
- codeapi/types/_swarm.py +85 -0
- codeapi/types/_time.py +46 -0
- codeapi/types/_zips.py +466 -0
- codeapi/types/py.typed +0 -0
- codeapi_client-0.4.1.dist-info/METADATA +14 -0
- codeapi_client-0.4.1.dist-info/RECORD +36 -0
- codeapi_client-0.4.1.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import time
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import TYPE_CHECKING, AsyncGenerator, List
|
|
7
|
+
|
|
8
|
+
import httpx
|
|
9
|
+
|
|
10
|
+
from codeapi.types import (
|
|
11
|
+
CodeAPIError,
|
|
12
|
+
CodeAPIException,
|
|
13
|
+
CodeType,
|
|
14
|
+
Job,
|
|
15
|
+
JobResult,
|
|
16
|
+
JobStage,
|
|
17
|
+
JobStatus,
|
|
18
|
+
JobType,
|
|
19
|
+
StreamOutput,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from . import AsyncClient
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class AsyncJobsClient:
|
|
27
|
+
def __init__(self, client: AsyncClient):
|
|
28
|
+
self._client = client
|
|
29
|
+
|
|
30
|
+
async def get(self, job_id: str) -> Job:
|
|
31
|
+
"""Gets a job.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
job_id (str): The ID of the job.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
Job: The job.
|
|
38
|
+
|
|
39
|
+
Raises:
|
|
40
|
+
HTTPException: If the request fails.
|
|
41
|
+
"""
|
|
42
|
+
url = f"{self._client.base_url}/jobs/{job_id}"
|
|
43
|
+
async with httpx.AsyncClient() as client:
|
|
44
|
+
try:
|
|
45
|
+
response = await client.get(url, headers=self._client.api_key_header)
|
|
46
|
+
response.raise_for_status()
|
|
47
|
+
return Job(**response.json())
|
|
48
|
+
except httpx.HTTPStatusError as e:
|
|
49
|
+
raise self._client._get_http_exception(httpx_error=e)
|
|
50
|
+
|
|
51
|
+
async def list(
|
|
52
|
+
self,
|
|
53
|
+
job_type: JobType | None = None,
|
|
54
|
+
job_status: JobStatus | None = None,
|
|
55
|
+
job_stage: JobStage | None = None,
|
|
56
|
+
) -> List[Job]:
|
|
57
|
+
"""Gets a list of jobs.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
job_type (JobType | None): Filter by job type.
|
|
61
|
+
job_status (JobStatus | None): Filter by job status.
|
|
62
|
+
job_stage (JobStage | None): Filter by job stage.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
list[Job]: List of jobs.
|
|
66
|
+
|
|
67
|
+
Raises:
|
|
68
|
+
HTTPException: If the request fails.
|
|
69
|
+
"""
|
|
70
|
+
url = f"{self._client.base_url}/jobs"
|
|
71
|
+
params = {}
|
|
72
|
+
if job_type is not None:
|
|
73
|
+
params["job_type"] = str(job_type)
|
|
74
|
+
if job_status is not None:
|
|
75
|
+
params["job_status"] = str(job_status)
|
|
76
|
+
if job_stage is not None:
|
|
77
|
+
params["job_stage"] = str(job_stage)
|
|
78
|
+
|
|
79
|
+
async with httpx.AsyncClient() as client:
|
|
80
|
+
try:
|
|
81
|
+
response = await client.get(
|
|
82
|
+
url, headers=self._client.api_key_header, params=params or None
|
|
83
|
+
)
|
|
84
|
+
response.raise_for_status()
|
|
85
|
+
return [Job(**item) for item in response.json()]
|
|
86
|
+
except httpx.HTTPStatusError as e:
|
|
87
|
+
raise self._client._get_http_exception(httpx_error=e)
|
|
88
|
+
|
|
89
|
+
async def get_url(self, job_id: str) -> str:
|
|
90
|
+
"""Gets the URL for a job.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
job_id (str): The job ID.
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
str: The job URL.
|
|
97
|
+
"""
|
|
98
|
+
return self._client.get_proxy_url(job_id)
|
|
99
|
+
|
|
100
|
+
async def get_status(self, job_id: str) -> JobStatus:
|
|
101
|
+
"""Gets the status of a job.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
job_id (str): The ID of the job.
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
JobStatus: The status of the job.
|
|
108
|
+
|
|
109
|
+
Raises:
|
|
110
|
+
HTTPException: If the request fails.
|
|
111
|
+
"""
|
|
112
|
+
url = f"{self._client.base_url}/jobs/{job_id}/status"
|
|
113
|
+
async with httpx.AsyncClient() as client:
|
|
114
|
+
try:
|
|
115
|
+
response = await client.get(url, headers=self._client.api_key_header)
|
|
116
|
+
response.raise_for_status()
|
|
117
|
+
return JobStatus(response.json())
|
|
118
|
+
except httpx.HTTPStatusError as e:
|
|
119
|
+
raise self._client._get_http_exception(httpx_error=e)
|
|
120
|
+
|
|
121
|
+
async def get_stage(self, job_id: str) -> JobStage:
|
|
122
|
+
"""Gets the stage of a job.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
job_id (str): The ID of the job.
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
JobStage: The stage of the job.
|
|
129
|
+
|
|
130
|
+
Raises:
|
|
131
|
+
HTTPException: If the request fails.
|
|
132
|
+
"""
|
|
133
|
+
url = f"{self._client.base_url}/jobs/{job_id}/stage"
|
|
134
|
+
async with httpx.AsyncClient() as client:
|
|
135
|
+
try:
|
|
136
|
+
response = await client.get(url, headers=self._client.api_key_header)
|
|
137
|
+
response.raise_for_status()
|
|
138
|
+
return JobStage(response.json())
|
|
139
|
+
except httpx.HTTPStatusError as e:
|
|
140
|
+
raise self._client._get_http_exception(httpx_error=e)
|
|
141
|
+
|
|
142
|
+
async def get_error(self, job_id: str) -> str | None:
|
|
143
|
+
"""Gets the error message of a job.
|
|
144
|
+
|
|
145
|
+
Args:
|
|
146
|
+
job_id (str): The ID of the job.
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
str | None: The error message of the job, or None if no error.
|
|
150
|
+
|
|
151
|
+
Raises:
|
|
152
|
+
HTTPException: If the request fails.
|
|
153
|
+
"""
|
|
154
|
+
url = f"{self._client.base_url}/jobs/{job_id}/error"
|
|
155
|
+
async with httpx.AsyncClient() as client:
|
|
156
|
+
try:
|
|
157
|
+
response = await client.get(url, headers=self._client.api_key_header)
|
|
158
|
+
response.raise_for_status()
|
|
159
|
+
return response.json()
|
|
160
|
+
except httpx.HTTPStatusError as e:
|
|
161
|
+
raise self._client._get_http_exception(httpx_error=e)
|
|
162
|
+
|
|
163
|
+
async def get_code_id(self, job_id: str) -> str | None:
|
|
164
|
+
"""Gets the code ID associated with a job.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
job_id (str): The ID of the job.
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
str | None: The code ID associated with the job, or None if no code ID.
|
|
171
|
+
|
|
172
|
+
Raises:
|
|
173
|
+
HTTPException: If the request fails.
|
|
174
|
+
"""
|
|
175
|
+
url = f"{self._client.base_url}/jobs/{job_id}/code_id"
|
|
176
|
+
async with httpx.AsyncClient() as client:
|
|
177
|
+
try:
|
|
178
|
+
response = await client.get(url, headers=self._client.api_key_header)
|
|
179
|
+
response.raise_for_status()
|
|
180
|
+
return response.json()
|
|
181
|
+
except httpx.HTTPStatusError as e:
|
|
182
|
+
raise self._client._get_http_exception(httpx_error=e)
|
|
183
|
+
|
|
184
|
+
async def get_result(
|
|
185
|
+
self, job_id: str, zip_path: Path | str | None = None
|
|
186
|
+
) -> JobResult:
|
|
187
|
+
"""Gets the result of a job and optionally saves it to a file.
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
job_id (str): The ID of the job.
|
|
191
|
+
zip_path (Path | str | None): The path to save the result zip file.
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
JobResult: The job result.
|
|
195
|
+
|
|
196
|
+
Raises:
|
|
197
|
+
HTTPException: If the request fails.
|
|
198
|
+
"""
|
|
199
|
+
url = f"{self._client.base_url}/jobs/{job_id}/result"
|
|
200
|
+
|
|
201
|
+
async with httpx.AsyncClient() as client:
|
|
202
|
+
try:
|
|
203
|
+
async with client.stream(
|
|
204
|
+
"GET", url, headers=self._client.api_key_header
|
|
205
|
+
) as response:
|
|
206
|
+
zip_bytes = await self._client._handle_stream_download_async(
|
|
207
|
+
response, zip_path
|
|
208
|
+
)
|
|
209
|
+
except httpx.HTTPStatusError as e:
|
|
210
|
+
raise self._client._get_http_exception(httpx_error=e)
|
|
211
|
+
|
|
212
|
+
return JobResult(zip_bytes=zip_bytes)
|
|
213
|
+
|
|
214
|
+
async def terminate(self, job_id: str) -> None:
|
|
215
|
+
"""Terminates a job.
|
|
216
|
+
|
|
217
|
+
Args:
|
|
218
|
+
job_id (str): The ID of the job.
|
|
219
|
+
|
|
220
|
+
Raises:
|
|
221
|
+
HTTPException: If the request fails.
|
|
222
|
+
"""
|
|
223
|
+
url = f"{self._client.base_url}/jobs/{job_id}/terminate"
|
|
224
|
+
|
|
225
|
+
async with httpx.AsyncClient() as client:
|
|
226
|
+
try:
|
|
227
|
+
response = await client.post(url, headers=self._client.api_key_header)
|
|
228
|
+
response.raise_for_status()
|
|
229
|
+
except httpx.HTTPStatusError as e:
|
|
230
|
+
raise self._client._get_http_exception(httpx_error=e)
|
|
231
|
+
|
|
232
|
+
async def stream_output(
|
|
233
|
+
self, job_id: str, read_timeout: float | None = 60
|
|
234
|
+
) -> AsyncGenerator[StreamOutput, None]:
|
|
235
|
+
"""Asynchronously yields stream output of a job line by line.
|
|
236
|
+
|
|
237
|
+
Args:
|
|
238
|
+
job_id (str): The ID of the job.
|
|
239
|
+
read_timeout (float | None): Read timeout for the stream request.
|
|
240
|
+
|
|
241
|
+
Yields:
|
|
242
|
+
StreamOutput: Stream output line by line.
|
|
243
|
+
|
|
244
|
+
Raises:
|
|
245
|
+
HTTPException: If the request fails.
|
|
246
|
+
"""
|
|
247
|
+
url = f"{self._client.base_url}/jobs/{job_id}/stream"
|
|
248
|
+
|
|
249
|
+
timeout = httpx.Timeout(connect=5.0, read=read_timeout, write=5.0, pool=5.0)
|
|
250
|
+
async with httpx.AsyncClient() as client:
|
|
251
|
+
async with client.stream(
|
|
252
|
+
"GET", url, timeout=timeout, headers=self._client.api_key_header
|
|
253
|
+
) as response:
|
|
254
|
+
async for line in response.aiter_lines():
|
|
255
|
+
if line.strip():
|
|
256
|
+
yield StreamOutput.model_validate_json(line)
|
|
257
|
+
|
|
258
|
+
async def await_stage(
|
|
259
|
+
self,
|
|
260
|
+
job_id: str,
|
|
261
|
+
timeout: float | None = None,
|
|
262
|
+
stage: JobStage = JobStage.POST_RUNNING,
|
|
263
|
+
) -> Job:
|
|
264
|
+
"""Waits for a job to reach a specific stage.
|
|
265
|
+
|
|
266
|
+
Args:
|
|
267
|
+
job_id (str): The ID of the job to wait for.
|
|
268
|
+
timeout (float | None): Maximum time to wait in seconds. If None, waits indefinitely.
|
|
269
|
+
stage (JobStage): The stage to wait for. Defaults to POST_RUNNING.
|
|
270
|
+
|
|
271
|
+
Returns:
|
|
272
|
+
Job: The final job object when the desired stage is reached.
|
|
273
|
+
|
|
274
|
+
Raises:
|
|
275
|
+
HTTPException: If the request fails.
|
|
276
|
+
APIException: If the job enters stage POST_RUNNING unexpectedly.
|
|
277
|
+
TimeoutError: If the timeout is exceeded.
|
|
278
|
+
"""
|
|
279
|
+
start_time = time.time()
|
|
280
|
+
|
|
281
|
+
while True:
|
|
282
|
+
job = await self.get(job_id)
|
|
283
|
+
current_stage = job.job_stage
|
|
284
|
+
if stage == JobStage.RUNNING and current_stage == JobStage.POST_RUNNING:
|
|
285
|
+
raise CodeAPIException(
|
|
286
|
+
error=CodeAPIError.JOB_POST_RUNNING,
|
|
287
|
+
message=f"Job {job_id} is in stage POST_RUNNING",
|
|
288
|
+
)
|
|
289
|
+
if current_stage in [stage, JobStage.POST_RUNNING, JobStage.UNKNOWN]:
|
|
290
|
+
return job
|
|
291
|
+
|
|
292
|
+
if timeout is not None:
|
|
293
|
+
elapsed_time = time.time() - start_time
|
|
294
|
+
if elapsed_time >= timeout:
|
|
295
|
+
raise TimeoutError(
|
|
296
|
+
f"Job {job_id} did not reach stage {stage} "
|
|
297
|
+
f"within {timeout} seconds"
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
await asyncio.sleep(1)
|
|
301
|
+
|
|
302
|
+
async def is_healthy(self, job_id: str) -> bool:
|
|
303
|
+
"""Checks whether a runner job is healthy.
|
|
304
|
+
|
|
305
|
+
Args:
|
|
306
|
+
job_id (str): The ID of the runner job.
|
|
307
|
+
|
|
308
|
+
Returns:
|
|
309
|
+
bool: True if runner job is healthy else False.
|
|
310
|
+
|
|
311
|
+
Raises:
|
|
312
|
+
HTTPException: If the request fails.
|
|
313
|
+
"""
|
|
314
|
+
url = f"{self._client.base_url}/{job_id}/ping"
|
|
315
|
+
async with httpx.AsyncClient() as client:
|
|
316
|
+
try:
|
|
317
|
+
response = await client.get(url, headers=self._client.api_key_header)
|
|
318
|
+
response.raise_for_status()
|
|
319
|
+
return response.status_code == 200
|
|
320
|
+
except Exception:
|
|
321
|
+
return False
|
|
322
|
+
|
|
323
|
+
async def await_healthy(self, job_id: str, timeout: float | None = None) -> Job:
|
|
324
|
+
"""Waits for a runner job to become healthy.
|
|
325
|
+
|
|
326
|
+
Args:
|
|
327
|
+
job_id (str): The ID of the runner job.
|
|
328
|
+
timeout (float | None): Maximum time to wait in seconds. If None, waits indefinitely.
|
|
329
|
+
|
|
330
|
+
Returns:
|
|
331
|
+
Job: The job object of the runner job.
|
|
332
|
+
|
|
333
|
+
Raises:
|
|
334
|
+
HTTPException: If the request fails.
|
|
335
|
+
APIException: If the job enters stage POST_RUNNING unexpectedly.
|
|
336
|
+
TimeoutError: If the timeout is exceeded.
|
|
337
|
+
"""
|
|
338
|
+
start_time = time.time()
|
|
339
|
+
|
|
340
|
+
while not await self.is_healthy(job_id=job_id):
|
|
341
|
+
job = await self._client.jobs.get(job_id)
|
|
342
|
+
if job.job_stage == JobStage.POST_RUNNING:
|
|
343
|
+
raise CodeAPIException(
|
|
344
|
+
error=CodeAPIError.JOB_POST_RUNNING,
|
|
345
|
+
message=f"Job {job_id} unexpectedly entered stage POST_RUNNING",
|
|
346
|
+
)
|
|
347
|
+
if timeout is not None:
|
|
348
|
+
elapsed_time = time.time() - start_time
|
|
349
|
+
if elapsed_time >= timeout:
|
|
350
|
+
raise TimeoutError(
|
|
351
|
+
f"Job {job_id} did not become healthy within {timeout} seconds"
|
|
352
|
+
)
|
|
353
|
+
await asyncio.sleep(1)
|
|
354
|
+
|
|
355
|
+
return await self._client.jobs.get(job_id)
|
|
356
|
+
|
|
357
|
+
async def get_latest(self, code_type: CodeType | None = None) -> Job | None:
|
|
358
|
+
"""Get the most recent job.
|
|
359
|
+
|
|
360
|
+
Args:
|
|
361
|
+
code_type (CodeType | None): Filter by code type.
|
|
362
|
+
|
|
363
|
+
Returns:
|
|
364
|
+
Job | None: The most recent job, or None if no jobs exist.
|
|
365
|
+
"""
|
|
366
|
+
job_type = JobType.from_code_type(code_type) if code_type else None
|
|
367
|
+
jobs = await self.list(job_type=job_type)
|
|
368
|
+
return jobs[0] if jobs else None
|
|
369
|
+
|
|
370
|
+
async def list_queued(self, code_type: CodeType | None = None) -> List[Job]:
|
|
371
|
+
"""Get all queued jobs.
|
|
372
|
+
|
|
373
|
+
Args:
|
|
374
|
+
code_type (CodeType | None): Filter by code type.
|
|
375
|
+
|
|
376
|
+
Returns:
|
|
377
|
+
List[Job]: List of queued jobs.
|
|
378
|
+
"""
|
|
379
|
+
job_type = JobType.from_code_type(code_type) if code_type else None
|
|
380
|
+
return await self.list(job_type=job_type, job_status=JobStatus.QUEUED)
|
|
381
|
+
|
|
382
|
+
async def list_scheduled(self, code_type: CodeType | None = None) -> List[Job]:
|
|
383
|
+
"""Get all scheduled jobs.
|
|
384
|
+
|
|
385
|
+
Args:
|
|
386
|
+
code_type (CodeType | None): Filter by code type.
|
|
387
|
+
|
|
388
|
+
Returns:
|
|
389
|
+
List[Job]: List of scheduled jobs.
|
|
390
|
+
"""
|
|
391
|
+
job_type = JobType.from_code_type(code_type) if code_type else None
|
|
392
|
+
return await self.list(job_type=job_type, job_status=JobStatus.SCHEDULED)
|
|
393
|
+
|
|
394
|
+
async def list_started(self, code_type: CodeType | None = None) -> List[Job]:
|
|
395
|
+
"""Get all started jobs.
|
|
396
|
+
|
|
397
|
+
Args:
|
|
398
|
+
code_type (CodeType | None): Filter by code type.
|
|
399
|
+
|
|
400
|
+
Returns:
|
|
401
|
+
List[Job]: List of started jobs.
|
|
402
|
+
"""
|
|
403
|
+
job_type = JobType.from_code_type(code_type) if code_type else None
|
|
404
|
+
return await self.list(job_type=job_type, job_status=JobStatus.STARTED)
|
|
405
|
+
|
|
406
|
+
async def list_deferred(self, code_type: CodeType | None = None) -> List[Job]:
|
|
407
|
+
"""Get all deferred jobs.
|
|
408
|
+
|
|
409
|
+
Args:
|
|
410
|
+
code_type (CodeType | None): Filter by code type.
|
|
411
|
+
|
|
412
|
+
Returns:
|
|
413
|
+
List[Job]: List of deferred jobs.
|
|
414
|
+
"""
|
|
415
|
+
job_type = JobType.from_code_type(code_type) if code_type else None
|
|
416
|
+
return await self.list(job_type=job_type, job_status=JobStatus.DEFERRED)
|
|
417
|
+
|
|
418
|
+
async def list_canceled(self, code_type: CodeType | None = None) -> List[Job]:
|
|
419
|
+
"""Get all canceled jobs.
|
|
420
|
+
|
|
421
|
+
Args:
|
|
422
|
+
code_type (CodeType | None): Filter by code type.
|
|
423
|
+
|
|
424
|
+
Returns:
|
|
425
|
+
List[Job]: List of canceled jobs.
|
|
426
|
+
"""
|
|
427
|
+
job_type = JobType.from_code_type(code_type) if code_type else None
|
|
428
|
+
return await self.list(job_type=job_type, job_status=JobStatus.CANCELED)
|
|
429
|
+
|
|
430
|
+
async def list_stopped(self, code_type: CodeType | None = None) -> List[Job]:
|
|
431
|
+
"""Get all stopped jobs.
|
|
432
|
+
|
|
433
|
+
Args:
|
|
434
|
+
code_type (CodeType | None): Filter by code type.
|
|
435
|
+
|
|
436
|
+
Returns:
|
|
437
|
+
List[Job]: List of stopped jobs.
|
|
438
|
+
"""
|
|
439
|
+
job_type = JobType.from_code_type(code_type) if code_type else None
|
|
440
|
+
return await self.list(job_type=job_type, job_status=JobStatus.STOPPED)
|
|
441
|
+
|
|
442
|
+
async def list_failed(self, code_type: CodeType | None = None) -> List[Job]:
|
|
443
|
+
"""Get all failed jobs.
|
|
444
|
+
|
|
445
|
+
Args:
|
|
446
|
+
code_type (CodeType | None): Filter by code type.
|
|
447
|
+
|
|
448
|
+
Returns:
|
|
449
|
+
List[Job]: List of failed jobs.
|
|
450
|
+
"""
|
|
451
|
+
job_type = JobType.from_code_type(code_type) if code_type else None
|
|
452
|
+
return await self.list(job_type=job_type, job_status=JobStatus.FAILED)
|
|
453
|
+
|
|
454
|
+
async def list_finished(self, code_type: CodeType | None = None) -> List[Job]:
|
|
455
|
+
"""Get all finished jobs.
|
|
456
|
+
|
|
457
|
+
Args:
|
|
458
|
+
code_type (CodeType | None): Filter by code type.
|
|
459
|
+
|
|
460
|
+
Returns:
|
|
461
|
+
List[Job]: List of finished jobs.
|
|
462
|
+
"""
|
|
463
|
+
job_type = JobType.from_code_type(code_type) if code_type else None
|
|
464
|
+
return await self.list(job_type=job_type, job_status=JobStatus.FINISHED)
|
|
465
|
+
|
|
466
|
+
async def list_timed_out(self, code_type: CodeType | None = None) -> List[Job]:
|
|
467
|
+
"""Get all timed out jobs.
|
|
468
|
+
|
|
469
|
+
Args:
|
|
470
|
+
code_type (CodeType | None): Filter by code type.
|
|
471
|
+
|
|
472
|
+
Returns:
|
|
473
|
+
List[Job]: List of timed out jobs.
|
|
474
|
+
"""
|
|
475
|
+
job_type = JobType.from_code_type(code_type) if code_type else None
|
|
476
|
+
return await self.list(job_type=job_type, job_status=JobStatus.TIMEOUT)
|
|
477
|
+
|
|
478
|
+
async def list_pre_running(self, code_type: CodeType | None = None) -> List[Job]:
|
|
479
|
+
"""Get all pre-running jobs.
|
|
480
|
+
|
|
481
|
+
Args:
|
|
482
|
+
code_type (CodeType | None): Filter by code type.
|
|
483
|
+
|
|
484
|
+
Returns:
|
|
485
|
+
List[Job]: List of pre-running jobs.
|
|
486
|
+
"""
|
|
487
|
+
job_type = JobType.from_code_type(code_type) if code_type else None
|
|
488
|
+
return await self.list(job_type=job_type, job_stage=JobStage.PRE_RUNNING)
|
|
489
|
+
|
|
490
|
+
async def list_running(self, code_type: CodeType | None = None) -> List[Job]:
|
|
491
|
+
"""Get all running jobs.
|
|
492
|
+
|
|
493
|
+
Args:
|
|
494
|
+
code_type (CodeType | None): Filter by code type.
|
|
495
|
+
|
|
496
|
+
Returns:
|
|
497
|
+
List[Job]: List of running jobs.
|
|
498
|
+
"""
|
|
499
|
+
job_type = JobType.from_code_type(code_type) if code_type else None
|
|
500
|
+
return await self.list(job_type=job_type, job_stage=JobStage.RUNNING)
|
|
501
|
+
|
|
502
|
+
async def list_post_running(self, code_type: CodeType | None = None) -> List[Job]:
|
|
503
|
+
"""Get all post-running jobs.
|
|
504
|
+
|
|
505
|
+
Args:
|
|
506
|
+
code_type (CodeType | None): Filter by code type.
|
|
507
|
+
|
|
508
|
+
Returns:
|
|
509
|
+
List[Job]: List of post-running jobs.
|
|
510
|
+
"""
|
|
511
|
+
job_type = JobType.from_code_type(code_type) if code_type else None
|
|
512
|
+
return await self.list(job_type=job_type, job_stage=JobStage.POST_RUNNING)
|