tilebox-workflows 0.43.0__py3-none-any.whl → 0.45.0__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.
- tilebox/workflows/__init__.py +2 -1
- tilebox/workflows/automations/client.py +3 -3
- tilebox/workflows/data.py +200 -46
- tilebox/workflows/formatting/__init__.py +0 -0
- tilebox/workflows/formatting/job.py +402 -0
- tilebox/workflows/jobs/client.py +41 -15
- tilebox/workflows/jobs/service.py +15 -6
- tilebox/workflows/runner/task_runner.py +54 -23
- tilebox/workflows/runner/task_service.py +4 -2
- tilebox/workflows/task.py +95 -14
- tilebox/workflows/workflows/v1/automation_pb2.py +22 -22
- tilebox/workflows/workflows/v1/automation_pb2.pyi +2 -2
- tilebox/workflows/workflows/v1/core_pb2.py +54 -30
- tilebox/workflows/workflows/v1/core_pb2.pyi +89 -16
- tilebox/workflows/workflows/v1/job_pb2.py +36 -38
- tilebox/workflows/workflows/v1/job_pb2.pyi +17 -17
- tilebox/workflows/workflows/v1/job_pb2_grpc.py +43 -0
- tilebox/workflows/workflows/v1/task_pb2.py +16 -16
- tilebox/workflows/workflows/v1/task_pb2.pyi +8 -6
- {tilebox_workflows-0.43.0.dist-info → tilebox_workflows-0.45.0.dist-info}/METADATA +3 -1
- {tilebox_workflows-0.43.0.dist-info → tilebox_workflows-0.45.0.dist-info}/RECORD +22 -20
- {tilebox_workflows-0.43.0.dist-info → tilebox_workflows-0.45.0.dist-info}/WHEEL +0 -0
tilebox/workflows/__init__.py
CHANGED
|
@@ -4,9 +4,10 @@ import sys
|
|
|
4
4
|
from loguru import logger
|
|
5
5
|
|
|
6
6
|
from tilebox.workflows.client import Client
|
|
7
|
+
from tilebox.workflows.data import Job
|
|
7
8
|
from tilebox.workflows.task import ExecutionContext, Task
|
|
8
9
|
|
|
9
|
-
__all__ = ["Client", "ExecutionContext", "Task"]
|
|
10
|
+
__all__ = ["Client", "ExecutionContext", "Job", "Task"]
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
def _init_logging(level: str = "INFO") -> None:
|
|
@@ -7,9 +7,9 @@ from tilebox.workflows.clusters.client import ClusterSlugLike, to_cluster_slug
|
|
|
7
7
|
from tilebox.workflows.data import (
|
|
8
8
|
AutomationPrototype,
|
|
9
9
|
CronTrigger,
|
|
10
|
+
SingleTaskSubmission,
|
|
10
11
|
StorageEventTrigger,
|
|
11
12
|
StorageLocation,
|
|
12
|
-
TaskSubmission,
|
|
13
13
|
)
|
|
14
14
|
from tilebox.workflows.task import _task_meta
|
|
15
15
|
|
|
@@ -76,7 +76,7 @@ class AutomationClient:
|
|
|
76
76
|
automation = AutomationPrototype(
|
|
77
77
|
id=UUID(int=0),
|
|
78
78
|
name=name,
|
|
79
|
-
prototype=
|
|
79
|
+
prototype=SingleTaskSubmission(
|
|
80
80
|
cluster_slug=to_cluster_slug(cluster or ""),
|
|
81
81
|
identifier=_task_meta(task).identifier,
|
|
82
82
|
input=task._serialize_args(), # noqa: SLF001
|
|
@@ -118,7 +118,7 @@ class AutomationClient:
|
|
|
118
118
|
automation = AutomationPrototype(
|
|
119
119
|
id=UUID(int=0),
|
|
120
120
|
name=name,
|
|
121
|
-
prototype=
|
|
121
|
+
prototype=SingleTaskSubmission(
|
|
122
122
|
cluster_slug=to_cluster_slug(cluster or ""),
|
|
123
123
|
identifier=_task_meta(task).identifier,
|
|
124
124
|
input=task._serialize_args(), # noqa: SLF001
|
tilebox/workflows/data.py
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import re
|
|
2
2
|
import warnings
|
|
3
|
+
from collections.abc import Callable
|
|
3
4
|
from dataclasses import dataclass, field
|
|
4
5
|
from datetime import datetime, timedelta
|
|
5
6
|
from enum import Enum
|
|
6
7
|
from functools import lru_cache
|
|
7
8
|
from pathlib import Path
|
|
9
|
+
from typing import Any, cast
|
|
8
10
|
from uuid import UUID
|
|
9
11
|
|
|
10
12
|
import boto3
|
|
@@ -21,7 +23,7 @@ from tilebox.datasets.query.time_interval import (
|
|
|
21
23
|
timedelta_to_duration,
|
|
22
24
|
timestamp_to_datetime,
|
|
23
25
|
)
|
|
24
|
-
from tilebox.datasets.uuid import
|
|
26
|
+
from tilebox.datasets.uuid import must_uuid_to_uuid_message, uuid_message_to_uuid, uuid_to_uuid_message
|
|
25
27
|
|
|
26
28
|
try:
|
|
27
29
|
# let's not make this a hard dependency, but if it's installed we can use its types
|
|
@@ -108,19 +110,19 @@ class TaskLease:
|
|
|
108
110
|
|
|
109
111
|
|
|
110
112
|
@dataclass(order=True)
|
|
111
|
-
class
|
|
113
|
+
class ProgressIndicator:
|
|
112
114
|
label: str | None
|
|
113
115
|
total: int
|
|
114
116
|
done: int
|
|
115
117
|
|
|
116
118
|
@classmethod
|
|
117
|
-
def from_message(cls,
|
|
118
|
-
"""Convert a
|
|
119
|
-
return cls(label=
|
|
119
|
+
def from_message(cls, progress_indicator: core_pb2.Progress) -> "ProgressIndicator":
|
|
120
|
+
"""Convert a ProgressIndicator protobuf message to a ProgressIndicator object."""
|
|
121
|
+
return cls(label=progress_indicator.label or None, total=progress_indicator.total, done=progress_indicator.done)
|
|
120
122
|
|
|
121
|
-
def to_message(self) -> core_pb2.
|
|
122
|
-
"""Convert a
|
|
123
|
-
return core_pb2.
|
|
123
|
+
def to_message(self) -> core_pb2.Progress:
|
|
124
|
+
"""Convert a ProgressIndicator object to a ProgressIndicator protobuf message."""
|
|
125
|
+
return core_pb2.Progress(label=self.label, total=self.total, done=self.done)
|
|
124
126
|
|
|
125
127
|
|
|
126
128
|
@dataclass(order=True)
|
|
@@ -160,7 +162,7 @@ class Task:
|
|
|
160
162
|
return core_pb2.Task(
|
|
161
163
|
id=uuid_to_uuid_message(self.id),
|
|
162
164
|
identifier=self.identifier.to_message(),
|
|
163
|
-
state=
|
|
165
|
+
state=cast(core_pb2.TaskState, self.state.value),
|
|
164
166
|
input=self.input,
|
|
165
167
|
display=self.display,
|
|
166
168
|
job=self.job.to_message() if self.job else None,
|
|
@@ -187,27 +189,81 @@ class Idling:
|
|
|
187
189
|
|
|
188
190
|
class JobState(Enum):
|
|
189
191
|
UNSPECIFIED = 0
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
192
|
+
SUBMITTED = 1
|
|
193
|
+
RUNNING = 2
|
|
194
|
+
STARTED = 3
|
|
195
|
+
COMPLETED = 4
|
|
196
|
+
FAILED = 5
|
|
197
|
+
CANCELED = 6
|
|
193
198
|
|
|
194
199
|
|
|
195
200
|
_JOB_STATES = {state.value: state for state in JobState}
|
|
196
201
|
|
|
202
|
+
# JobState.QUEUED is deprecated and has been renamed to SUBMITTED, but we keep it around for backwards compatibility
|
|
203
|
+
JobState.QUEUED = JobState.SUBMITTED # type: ignore[assignment]
|
|
197
204
|
|
|
198
|
-
|
|
205
|
+
|
|
206
|
+
@dataclass(order=True, frozen=True)
|
|
207
|
+
class ExecutionStats:
|
|
208
|
+
first_task_started_at: datetime | None
|
|
209
|
+
last_task_stopped_at: datetime | None
|
|
210
|
+
compute_time: timedelta
|
|
211
|
+
elapsed_time: timedelta
|
|
212
|
+
parallelism: float
|
|
213
|
+
total_tasks: int
|
|
214
|
+
tasks_by_state: dict[TaskState, int]
|
|
215
|
+
|
|
216
|
+
@classmethod
|
|
217
|
+
def from_message(cls, execution_stats: core_pb2.ExecutionStats) -> "ExecutionStats":
|
|
218
|
+
"""Convert a ExecutionStats protobuf message to a ExecutionStats object."""
|
|
219
|
+
return cls(
|
|
220
|
+
first_task_started_at=timestamp_to_datetime(execution_stats.first_task_started_at)
|
|
221
|
+
if execution_stats.HasField("first_task_started_at")
|
|
222
|
+
else None,
|
|
223
|
+
last_task_stopped_at=timestamp_to_datetime(execution_stats.last_task_stopped_at)
|
|
224
|
+
if execution_stats.HasField("last_task_stopped_at")
|
|
225
|
+
else None,
|
|
226
|
+
compute_time=duration_to_timedelta(execution_stats.compute_time),
|
|
227
|
+
elapsed_time=duration_to_timedelta(execution_stats.elapsed_time),
|
|
228
|
+
parallelism=execution_stats.parallelism,
|
|
229
|
+
total_tasks=execution_stats.total_tasks,
|
|
230
|
+
tasks_by_state={_TASK_STATES[state.state]: state.count for state in execution_stats.tasks_by_state},
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
def to_message(self) -> core_pb2.ExecutionStats:
|
|
234
|
+
"""Convert a ExecutionStats object to a ExecutionStats protobuf message."""
|
|
235
|
+
return core_pb2.ExecutionStats(
|
|
236
|
+
first_task_started_at=datetime_to_timestamp(self.first_task_started_at)
|
|
237
|
+
if self.first_task_started_at
|
|
238
|
+
else None,
|
|
239
|
+
last_task_stopped_at=datetime_to_timestamp(self.last_task_stopped_at)
|
|
240
|
+
if self.last_task_stopped_at
|
|
241
|
+
else None,
|
|
242
|
+
compute_time=timedelta_to_duration(self.compute_time),
|
|
243
|
+
elapsed_time=timedelta_to_duration(self.elapsed_time),
|
|
244
|
+
parallelism=self.parallelism,
|
|
245
|
+
total_tasks=self.total_tasks,
|
|
246
|
+
tasks_by_state=[
|
|
247
|
+
core_pb2.TaskStateCount(state=cast(core_pb2.TaskState, state.value), count=count)
|
|
248
|
+
for state, count in self.tasks_by_state.items()
|
|
249
|
+
],
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
@dataclass(order=True, frozen=True)
|
|
199
254
|
class Job:
|
|
200
255
|
id: UUID
|
|
201
256
|
name: str
|
|
202
257
|
trace_parent: str
|
|
203
258
|
state: JobState
|
|
204
259
|
submitted_at: datetime
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
progress_bars: list[ProgressBar]
|
|
260
|
+
progress: list[ProgressIndicator]
|
|
261
|
+
execution_stats: ExecutionStats
|
|
208
262
|
|
|
209
263
|
@classmethod
|
|
210
|
-
def from_message(
|
|
264
|
+
def from_message(
|
|
265
|
+
cls, job: core_pb2.Job, **extra_kwargs: Any
|
|
266
|
+
) -> "Job": # lets use typing.Self once we require python >= 3.11
|
|
211
267
|
"""Convert a Job protobuf message to a Job object."""
|
|
212
268
|
return cls(
|
|
213
269
|
id=uuid_message_to_uuid(job.id),
|
|
@@ -215,9 +271,9 @@ class Job:
|
|
|
215
271
|
trace_parent=job.trace_parent,
|
|
216
272
|
state=_JOB_STATES[job.state],
|
|
217
273
|
submitted_at=timestamp_to_datetime(job.submitted_at),
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
274
|
+
progress=[ProgressIndicator.from_message(progress) for progress in job.progress],
|
|
275
|
+
execution_stats=ExecutionStats.from_message(job.execution_stats),
|
|
276
|
+
**extra_kwargs,
|
|
221
277
|
)
|
|
222
278
|
|
|
223
279
|
def to_message(self) -> core_pb2.Job:
|
|
@@ -226,12 +282,32 @@ class Job:
|
|
|
226
282
|
id=uuid_to_uuid_message(self.id),
|
|
227
283
|
name=self.name,
|
|
228
284
|
trace_parent=self.trace_parent,
|
|
229
|
-
state=
|
|
285
|
+
state=cast(core_pb2.JobState, self.state.value),
|
|
230
286
|
submitted_at=datetime_to_timestamp(self.submitted_at),
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
287
|
+
progress=[progress.to_message() for progress in self.progress],
|
|
288
|
+
execution_stats=self.execution_stats.to_message(),
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
@property
|
|
292
|
+
def canceled(self) -> bool:
|
|
293
|
+
warnings.warn(
|
|
294
|
+
"The canceled property on a job has been deprecated, and will be removed in a future version. "
|
|
295
|
+
"Use job.state == JobState.CANCELED, or job.state == JobState.FAILED instead.",
|
|
296
|
+
DeprecationWarning,
|
|
297
|
+
stacklevel=2,
|
|
298
|
+
)
|
|
299
|
+
# the deprecated canceled property was also true for failed jobs, so we keep that behavior
|
|
300
|
+
return self.state in (JobState.CANCELED, JobState.FAILED)
|
|
301
|
+
|
|
302
|
+
@property
|
|
303
|
+
def started_at(self) -> datetime | None:
|
|
304
|
+
warnings.warn(
|
|
305
|
+
"The started_at property on a job has been deprecated, use `job.execution_stats.first_task_started_at` "
|
|
306
|
+
"instead.",
|
|
307
|
+
DeprecationWarning,
|
|
308
|
+
stacklevel=2,
|
|
234
309
|
)
|
|
310
|
+
return self.execution_stats.first_task_started_at
|
|
235
311
|
|
|
236
312
|
|
|
237
313
|
@dataclass(order=True)
|
|
@@ -266,7 +342,69 @@ class NextTaskToRun:
|
|
|
266
342
|
|
|
267
343
|
|
|
268
344
|
@dataclass
|
|
269
|
-
class
|
|
345
|
+
class TaskSubmissionGroup:
|
|
346
|
+
dependencies_on_other_groups: list[int]
|
|
347
|
+
inputs: list[bytes] = field(default_factory=list)
|
|
348
|
+
identifier_pointers: list[int] = field(default_factory=list)
|
|
349
|
+
cluster_slug_pointers: list[int] = field(default_factory=list)
|
|
350
|
+
display_pointers: list[int] = field(default_factory=list)
|
|
351
|
+
max_retries_values: list[int] = field(default_factory=list)
|
|
352
|
+
|
|
353
|
+
@classmethod
|
|
354
|
+
def from_message(cls, group: core_pb2.TaskSubmissionGroup) -> "TaskSubmissionGroup":
|
|
355
|
+
"""Convert a TaskSubmissionGroup protobuf message to a TaskSubmissionGroup object."""
|
|
356
|
+
return cls(
|
|
357
|
+
dependencies_on_other_groups=list(group.dependencies_on_other_groups),
|
|
358
|
+
inputs=list(group.inputs),
|
|
359
|
+
identifier_pointers=list(group.identifier_pointers),
|
|
360
|
+
cluster_slug_pointers=list(group.cluster_slug_pointers),
|
|
361
|
+
display_pointers=list(group.display_pointers),
|
|
362
|
+
max_retries_values=list(group.max_retries_values),
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
def to_message(self) -> core_pb2.TaskSubmissionGroup:
|
|
366
|
+
"""Convert a TaskSubmissionGroup object to a TaskSubmissionGroup protobuf message."""
|
|
367
|
+
return core_pb2.TaskSubmissionGroup(
|
|
368
|
+
dependencies_on_other_groups=self.dependencies_on_other_groups,
|
|
369
|
+
inputs=self.inputs,
|
|
370
|
+
identifier_pointers=self.identifier_pointers,
|
|
371
|
+
cluster_slug_pointers=self.cluster_slug_pointers,
|
|
372
|
+
display_pointers=self.display_pointers,
|
|
373
|
+
max_retries_values=self.max_retries_values,
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
@dataclass
|
|
378
|
+
class TaskSubmissions:
|
|
379
|
+
task_groups: list[TaskSubmissionGroup]
|
|
380
|
+
cluster_slug_lookup: list[str]
|
|
381
|
+
identifier_lookup: list[TaskIdentifier]
|
|
382
|
+
display_lookup: list[str]
|
|
383
|
+
|
|
384
|
+
@classmethod
|
|
385
|
+
def from_message(cls, sub_task: core_pb2.TaskSubmissions) -> "TaskSubmissions":
|
|
386
|
+
"""Convert a TaskSubmission protobuf message to a TaskSubmission object."""
|
|
387
|
+
return cls(
|
|
388
|
+
task_groups=[TaskSubmissionGroup.from_message(group) for group in sub_task.task_groups],
|
|
389
|
+
cluster_slug_lookup=list(sub_task.cluster_slug_lookup),
|
|
390
|
+
identifier_lookup=[TaskIdentifier.from_message(identifier) for identifier in sub_task.identifier_lookup],
|
|
391
|
+
display_lookup=list(sub_task.display_lookup),
|
|
392
|
+
)
|
|
393
|
+
|
|
394
|
+
def to_message(self) -> core_pb2.TaskSubmissions:
|
|
395
|
+
"""Convert a TaskSubmissions object to a TaskSubmissions protobuf message."""
|
|
396
|
+
return core_pb2.TaskSubmissions(
|
|
397
|
+
task_groups=[group.to_message() for group in self.task_groups],
|
|
398
|
+
cluster_slug_lookup=self.cluster_slug_lookup,
|
|
399
|
+
identifier_lookup=[identifier.to_message() for identifier in self.identifier_lookup],
|
|
400
|
+
display_lookup=self.display_lookup,
|
|
401
|
+
)
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
@dataclass
|
|
405
|
+
class SingleTaskSubmission:
|
|
406
|
+
"""A submission of a single task. Used for automations."""
|
|
407
|
+
|
|
270
408
|
cluster_slug: str
|
|
271
409
|
identifier: TaskIdentifier
|
|
272
410
|
input: bytes
|
|
@@ -275,8 +413,8 @@ class TaskSubmission:
|
|
|
275
413
|
max_retries: int = 0
|
|
276
414
|
|
|
277
415
|
@classmethod
|
|
278
|
-
def from_message(cls, sub_task: core_pb2.
|
|
279
|
-
"""Convert a TaskSubmission protobuf message to a
|
|
416
|
+
def from_message(cls, sub_task: core_pb2.SingleTaskSubmission) -> "SingleTaskSubmission":
|
|
417
|
+
"""Convert a TaskSubmission protobuf message to a SingleTaskSubmission object."""
|
|
280
418
|
return cls(
|
|
281
419
|
cluster_slug=sub_task.cluster_slug,
|
|
282
420
|
identifier=TaskIdentifier.from_message(sub_task.identifier),
|
|
@@ -286,9 +424,9 @@ class TaskSubmission:
|
|
|
286
424
|
max_retries=sub_task.max_retries,
|
|
287
425
|
)
|
|
288
426
|
|
|
289
|
-
def to_message(self) -> core_pb2.
|
|
290
|
-
"""Convert a
|
|
291
|
-
return core_pb2.
|
|
427
|
+
def to_message(self) -> core_pb2.SingleTaskSubmission:
|
|
428
|
+
"""Convert a SingleTaskSubmission object to a TaskSubmission protobuf message."""
|
|
429
|
+
return core_pb2.SingleTaskSubmission(
|
|
292
430
|
cluster_slug=self.cluster_slug,
|
|
293
431
|
identifier=self.identifier.to_message(),
|
|
294
432
|
input=self.input,
|
|
@@ -302,8 +440,8 @@ class TaskSubmission:
|
|
|
302
440
|
class ComputedTask:
|
|
303
441
|
id: UUID
|
|
304
442
|
display: str | None
|
|
305
|
-
sub_tasks:
|
|
306
|
-
progress_updates: list[
|
|
443
|
+
sub_tasks: TaskSubmissions | None
|
|
444
|
+
progress_updates: list[ProgressIndicator]
|
|
307
445
|
|
|
308
446
|
@classmethod
|
|
309
447
|
def from_message(cls, computed_task: task_pb2.ComputedTask) -> "ComputedTask":
|
|
@@ -311,8 +449,10 @@ class ComputedTask:
|
|
|
311
449
|
return cls(
|
|
312
450
|
id=uuid_message_to_uuid(computed_task.id),
|
|
313
451
|
display=computed_task.display,
|
|
314
|
-
sub_tasks=
|
|
315
|
-
|
|
452
|
+
sub_tasks=TaskSubmissions.from_message(computed_task.sub_tasks)
|
|
453
|
+
if computed_task.HasField("sub_tasks")
|
|
454
|
+
else None,
|
|
455
|
+
progress_updates=[ProgressIndicator.from_message(progress) for progress in computed_task.progress_updates],
|
|
316
456
|
)
|
|
317
457
|
|
|
318
458
|
def to_message(self) -> task_pb2.ComputedTask:
|
|
@@ -320,7 +460,7 @@ class ComputedTask:
|
|
|
320
460
|
return task_pb2.ComputedTask(
|
|
321
461
|
id=uuid_to_uuid_message(self.id),
|
|
322
462
|
display=self.display,
|
|
323
|
-
sub_tasks=
|
|
463
|
+
sub_tasks=self.sub_tasks.to_message() if self.sub_tasks else None,
|
|
324
464
|
progress_updates=[progress.to_message() for progress in self.progress_updates],
|
|
325
465
|
)
|
|
326
466
|
|
|
@@ -500,7 +640,7 @@ class TriggeredCronEvent:
|
|
|
500
640
|
class AutomationPrototype:
|
|
501
641
|
id: UUID
|
|
502
642
|
name: str
|
|
503
|
-
prototype:
|
|
643
|
+
prototype: SingleTaskSubmission
|
|
504
644
|
storage_event_triggers: list[StorageEventTrigger]
|
|
505
645
|
cron_triggers: list[CronTrigger]
|
|
506
646
|
|
|
@@ -510,7 +650,7 @@ class AutomationPrototype:
|
|
|
510
650
|
return cls(
|
|
511
651
|
id=uuid_message_to_uuid(task.id),
|
|
512
652
|
name=task.name,
|
|
513
|
-
prototype=
|
|
653
|
+
prototype=SingleTaskSubmission.from_message(task.prototype),
|
|
514
654
|
storage_event_triggers=[
|
|
515
655
|
StorageEventTrigger.from_message(trigger) for trigger in task.storage_event_triggers
|
|
516
656
|
],
|
|
@@ -571,9 +711,13 @@ class QueryJobsResponse:
|
|
|
571
711
|
next_page: Pagination
|
|
572
712
|
|
|
573
713
|
@classmethod
|
|
574
|
-
def from_message(
|
|
714
|
+
def from_message(
|
|
715
|
+
cls,
|
|
716
|
+
page: job_pb2.QueryJobsResponse,
|
|
717
|
+
job_factory: Callable[[core_pb2.Job], Job] = Job.from_message,
|
|
718
|
+
) -> "QueryJobsResponse":
|
|
575
719
|
return cls(
|
|
576
|
-
jobs=[
|
|
720
|
+
jobs=[job_factory(job) for job in page.jobs],
|
|
577
721
|
next_page=Pagination.from_message(page.next_page),
|
|
578
722
|
)
|
|
579
723
|
|
|
@@ -586,21 +730,31 @@ class QueryJobsResponse:
|
|
|
586
730
|
|
|
587
731
|
@dataclass(frozen=True)
|
|
588
732
|
class QueryFilters:
|
|
589
|
-
time_interval: TimeInterval | None
|
|
590
|
-
id_interval: IDInterval | None
|
|
591
|
-
|
|
733
|
+
time_interval: TimeInterval | None
|
|
734
|
+
id_interval: IDInterval | None
|
|
735
|
+
automation_ids: list[UUID]
|
|
736
|
+
job_states: list[JobState]
|
|
737
|
+
name: str | None
|
|
592
738
|
|
|
593
739
|
@classmethod
|
|
594
740
|
def from_message(cls, filters: job_pb2.QueryFilters) -> "QueryFilters":
|
|
595
741
|
return cls(
|
|
596
|
-
time_interval=TimeInterval.from_message(filters.time_interval)
|
|
597
|
-
|
|
598
|
-
|
|
742
|
+
time_interval=TimeInterval.from_message(filters.time_interval)
|
|
743
|
+
if filters.HasField("time_interval")
|
|
744
|
+
else None,
|
|
745
|
+
id_interval=IDInterval.from_message(filters.id_interval) if filters.HasField("id_interval") else None,
|
|
746
|
+
automation_ids=[uuid_message_to_uuid(uuid) for uuid in filters.automation_ids],
|
|
747
|
+
job_states=[_JOB_STATES[state] for state in filters.states],
|
|
748
|
+
name=filters.name or None,
|
|
599
749
|
)
|
|
600
750
|
|
|
601
751
|
def to_message(self) -> job_pb2.QueryFilters:
|
|
602
752
|
return job_pb2.QueryFilters(
|
|
603
753
|
time_interval=self.time_interval.to_message() if self.time_interval else None,
|
|
604
754
|
id_interval=self.id_interval.to_message() if self.id_interval else None,
|
|
605
|
-
|
|
755
|
+
automation_ids=[must_uuid_to_uuid_message(uuid) for uuid in self.automation_ids]
|
|
756
|
+
if self.automation_ids
|
|
757
|
+
else None,
|
|
758
|
+
states=[cast(core_pb2.JobState, state.value) for state in self.job_states] if self.job_states else None,
|
|
759
|
+
name=self.name or None, # empty string becomes None
|
|
606
760
|
)
|
|
File without changes
|