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