Skip to content

Commit d21f9e3

Browse files
feat: add sort parameter to simulators API list and iteration methods (#2355)
1 parent be9a1e4 commit d21f9e3

10 files changed

Lines changed: 91 additions & 10 deletions

File tree

cognite/client/_api/simulators/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ def __call__(
189189
resource_cls=SimulatorModel,
190190
method="POST",
191191
filter=model_filter.dump(),
192+
sort=[PropertySort.load(sort).dump()] if sort else None,
192193
chunk_size=chunk_size,
193194
limit=limit,
194195
)

cognite/client/_api/simulators/models_revisions.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ def __call__(
220220
resource_cls=SimulatorModelRevision,
221221
method="POST",
222222
filter=model_revisions_filter.dump(),
223+
sort=[PropertySort.load(sort).dump()] if sort else None,
223224
chunk_size=chunk_size,
224225
limit=limit,
225226
)

cognite/client/_api/simulators/routines.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ def __call__(
5454
chunk_size: int,
5555
model_external_ids: Sequence[str] | None = None,
5656
simulator_integration_external_ids: Sequence[str] | None = None,
57+
sort: PropertySort | None = None,
5758
limit: int | None = None,
5859
) -> Iterator[SimulatorRoutineList]: ...
5960

@@ -63,6 +64,7 @@ def __call__(
6364
chunk_size: None = None,
6465
model_external_ids: Sequence[str] | None = None,
6566
simulator_integration_external_ids: Sequence[str] | None = None,
67+
sort: PropertySort | None = None,
6668
limit: int | None = None,
6769
) -> Iterator[SimulatorRoutine]: ...
6870

@@ -71,6 +73,7 @@ def __call__(
7173
chunk_size: int | None = None,
7274
model_external_ids: Sequence[str] | None = None,
7375
simulator_integration_external_ids: Sequence[str] | None = None,
76+
sort: PropertySort | None = None,
7477
limit: int | None = None,
7578
) -> Iterator[SimulatorRoutine] | Iterator[SimulatorRoutineList]:
7679
"""Iterate over simulator routines
@@ -81,6 +84,7 @@ def __call__(
8184
chunk_size (int | None): Number of simulator routines to return in each chunk. Defaults to yielding one simulator routine a time.
8285
model_external_ids (Sequence[str] | None): Filter on model external ids.
8386
simulator_integration_external_ids (Sequence[str] | None): Filter on simulator integration external ids.
87+
sort (PropertySort | None): The criteria to sort by.
8488
limit (int | None): Maximum number of simulator routines to return. Defaults to return all items.
8589
8690
Returns:
@@ -96,6 +100,7 @@ def __call__(
96100
resource_cls=SimulatorRoutine,
97101
method="POST",
98102
filter=routines_filter.dump(),
103+
sort=[PropertySort.load(sort).dump()] if sort else None,
99104
chunk_size=chunk_size,
100105
limit=limit,
101106
)

cognite/client/_api/simulators/runs.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from cognite.client._api_client import APIClient
77
from cognite.client._constants import DEFAULT_LIMIT_READ
88
from cognite.client.data_classes.shared import TimestampRange
9-
from cognite.client.data_classes.simulators.filters import SimulatorRunsFilter
9+
from cognite.client.data_classes.simulators.filters import SimulationRunsSort, SimulatorRunsFilter
1010
from cognite.client.data_classes.simulators.runs import (
1111
SimulationRun,
1212
SimulationRunDataList,
@@ -67,6 +67,7 @@ def __call__(
6767
model_revision_external_ids: SequenceNotStr[str] | None = None,
6868
created_time: TimestampRange | None = None,
6969
simulation_time: TimestampRange | None = None,
70+
sort: SimulationRunsSort | None = None,
7071
) -> Iterator[SimulationRunList]: ...
7172

7273
@overload
@@ -84,6 +85,7 @@ def __call__(
8485
model_revision_external_ids: SequenceNotStr[str] | None = None,
8586
created_time: TimestampRange | None = None,
8687
simulation_time: TimestampRange | None = None,
88+
sort: SimulationRunsSort | None = None,
8789
) -> Iterator[SimulationRun]: ...
8890

8991
def __call__(
@@ -100,6 +102,7 @@ def __call__(
100102
model_revision_external_ids: SequenceNotStr[str] | None = None,
101103
created_time: TimestampRange | None = None,
102104
simulation_time: TimestampRange | None = None,
105+
sort: SimulationRunsSort | None = None,
103106
) -> Iterator[SimulationRun] | Iterator[SimulationRunList]:
104107
"""Iterate over simulation runs
105108
@@ -118,6 +121,7 @@ def __call__(
118121
model_revision_external_ids (SequenceNotStr[str] | None): Filter by model revision external ids
119122
created_time (TimestampRange | None): Filter by created time
120123
simulation_time (TimestampRange | None): Filter by simulation time
124+
sort (SimulationRunsSort | None): The criteria to sort by.
121125
122126
Returns:
123127
Iterator[SimulationRun] | Iterator[SimulationRunList]: yields Simulation Run one by one if chunk is not specified, else SimulatorRunsList objects.
@@ -141,6 +145,7 @@ def __call__(
141145
resource_cls=SimulationRun,
142146
method="POST",
143147
filter=filter_runs.dump(),
148+
sort=[SimulationRunsSort.load(sort).dump()] if sort else None,
144149
chunk_size=chunk_size,
145150
limit=limit,
146151
)
@@ -158,6 +163,7 @@ def list(
158163
model_revision_external_ids: SequenceNotStr[str] | None = None,
159164
created_time: TimestampRange | None = None,
160165
simulation_time: TimestampRange | None = None,
166+
sort: SimulationRunsSort | None = None,
161167
) -> SimulationRunList:
162168
"""`Filter simulation runs <https://developer.cognite.com/api#tag/Simulation-Runs/operation/filter_simulation_runs_simulators_runs_list_post>`_
163169
@@ -175,6 +181,7 @@ def list(
175181
model_revision_external_ids (SequenceNotStr[str] | None): Filter by model revision external ids
176182
created_time (TimestampRange | None): Filter by created time
177183
simulation_time (TimestampRange | None): Filter by simulation time
184+
sort (SimulationRunsSort | None): The criteria to sort by.
178185
179186
Returns:
180187
SimulationRunList: List of simulation runs
@@ -218,6 +225,7 @@ def list(
218225
resource_cls=SimulationRun,
219226
list_cls=SimulationRunList,
220227
filter=filter_runs.dump(),
228+
sort=[SimulationRunsSort.load(sort).dump()] if sort else None,
221229
)
222230

223231
@overload

cognite/client/data_classes/simulators/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from cognite.client.data_classes.simulators.filters import (
44
PropertySort,
5+
SimulationRunsSort,
56
SimulatorIntegrationFilter,
67
SimulatorModelRevisionsFilter,
78
SimulatorModelsFilter,
@@ -37,12 +38,12 @@
3738
)
3839

3940
__all__ = [
40-
"PropertySort",
4141
"PropertySort",
4242
"SimulationRun",
4343
"SimulationRunList",
4444
"SimulationRunWrite",
4545
"SimulationRunWriteList",
46+
"SimulationRunsSort",
4647
"Simulator",
4748
"SimulatorIntegration",
4849
"SimulatorIntegrationFilter",

cognite/client/data_classes/simulators/filters.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
from __future__ import annotations
22

33
from collections.abc import Sequence
4-
from typing import Any, Literal
4+
from typing import Any, Literal, cast
55

66
from cognite.client.data_classes._base import CogniteFilter, CogniteSort
77
from cognite.client.data_classes.shared import TimestampRange
8+
from cognite.client.utils._text import to_camel_case
89
from cognite.client.utils.useful_types import SequenceNotStr
910

1011

@@ -91,14 +92,30 @@ def __init__(
9192
class PropertySort(CogniteSort):
9293
def __init__(
9394
self,
94-
property: Literal["createdTime"] = "createdTime",
95+
property: Literal["created_time"] = "created_time",
9596
order: Literal["asc", "desc"] = "asc",
9697
):
9798
super().__init__(property, order)
9899

99100
def dump(self, camel_case: bool = True) -> dict[str, Any]:
100101
dumped = super().dump(camel_case=camel_case)
101-
dumped["property"] = self.property
102+
prop = cast(str, self.property)
103+
dumped["property"] = to_camel_case(prop) if camel_case else prop
104+
return dumped
105+
106+
107+
class SimulationRunsSort(CogniteSort):
108+
def __init__(
109+
self,
110+
property: Literal["created_time", "simulation_time"] = "created_time",
111+
order: Literal["asc", "desc"] = "asc",
112+
):
113+
super().__init__(property, order)
114+
115+
def dump(self, camel_case: bool = True) -> dict[str, Any]:
116+
dumped = super().dump(camel_case=camel_case)
117+
prop = cast(str, self.property)
118+
dumped["property"] = to_camel_case(prop) if camel_case else prop
102119
return dumped
103120

104121

tests/tests_integration/test_api/test_simulators/test_models.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ def test_list_models(self, cognite_client: CogniteClient, seed_resource_names: R
4141
for model in cognite_client.simulators.models(
4242
limit=2,
4343
simulator_external_ids=[seed_resource_names.simulator_external_id],
44+
sort=PropertySort(order="asc", property="created_time"),
4445
):
4546
assert model.created_time is not None
4647
model_ids.append(model.id)
@@ -72,7 +73,10 @@ def test_list_model_revisions(self, cognite_client: CogniteClient, seed_resource
7273
)
7374

7475
model_revision_ids = []
75-
for revision in cognite_client.simulators.models.revisions(limit=2):
76+
for revision in cognite_client.simulators.models.revisions(
77+
limit=2,
78+
sort=PropertySort(order="desc", property="created_time"),
79+
):
7680
assert revision.created_time is not None
7781
model_revision_ids.append(revision.id)
7882

@@ -105,13 +109,13 @@ def test_list_model_revisions_filtering_sort(
105109
self, cognite_client: CogniteClient, seed_resource_names: ResourceNames
106110
) -> None:
107111
revisions_asc = cognite_client.simulators.models.revisions.list(
108-
sort=PropertySort(order="asc", property="createdTime"),
112+
sort=PropertySort(order="asc", property="created_time"),
109113
model_external_ids=[seed_resource_names.simulator_model_external_id],
110114
all_versions=True,
111115
)
112116

113117
revisions_desc = cognite_client.simulators.models.revisions.list(
114-
sort=PropertySort(order="desc", property="createdTime"),
118+
sort=PropertySort(order="desc", property="created_time"),
115119
model_external_ids=[seed_resource_names.simulator_model_external_id],
116120
all_versions=True,
117121
)

tests/tests_integration/test_api/test_simulators/test_routine_revisions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def test_list_and_filtering_routine_revisions(
3838
revisions_by_model: list[SimulatorRoutineRevision] = []
3939

4040
for revision in cognite_client.simulators.routines.revisions(
41-
sort=PropertySort(order="asc", property="createdTime"),
41+
sort=PropertySort(order="asc", property="created_time"),
4242
model_external_ids=[model_external_id],
4343
all_versions=True,
4444
include_all_fields=True,

tests/tests_integration/test_api/test_simulators/test_routines.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from itertools import pairwise
2+
13
import pytest
24

35
from cognite.client._cognite_client import CogniteClient
@@ -46,9 +48,22 @@ def test_sort(
4648

4749
routines_asc = cognite_client.simulators.routines.list(
4850
simulator_integration_external_ids=[simulator_integration_unique_external_id],
49-
sort=PropertySort(order="asc", property="createdTime"),
51+
sort=PropertySort(order="asc", property="created_time"),
5052
)
5153

5254
assert len(routines_asc) > 1
5355
for i in range(1, len(routines_asc)):
5456
assert routines_asc[i].created_time >= routines_asc[i - 1].created_time
57+
58+
# Test iterator with sort
59+
routines_iter = list(
60+
cognite_client.simulators.routines(
61+
simulator_integration_external_ids=[simulator_integration_unique_external_id],
62+
sort=PropertySort(order="asc", property="created_time"),
63+
limit=3,
64+
)
65+
)
66+
67+
assert len(routines_iter) == 3
68+
for prev, curr in pairwise(routines_iter):
69+
assert curr.created_time >= prev.created_time

tests/tests_integration/test_api/test_simulators/test_runs.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import asyncio
22
import time
3+
from itertools import pairwise
34

45
import pytest
56

67
from cognite.client._cognite_client import CogniteClient
78
from cognite.client.data_classes import TimestampRange
9+
from cognite.client.data_classes.simulators.filters import SimulationRunsSort
810
from cognite.client.data_classes.simulators.routine_revisions import SimulatorRoutineRevision
911
from cognite.client.data_classes.simulators.runs import (
1012
SimulationInput,
@@ -181,6 +183,33 @@ def test_list_filtering_timestamp_ranges(
181183
)
182184
assert len(runs_empty_range) == 0
183185

186+
def test_list_sort(self, cognite_client: CogniteClient, seed_resource_names: ResourceNames) -> None:
187+
routine_external_id = seed_resource_names.simulator_routine_external_id
188+
189+
# Test list with sort by createdTime
190+
runs_asc = cognite_client.simulators.runs.list(
191+
routine_external_ids=[routine_external_id],
192+
sort=SimulationRunsSort(order="asc", property="created_time"),
193+
limit=5,
194+
)
195+
196+
if len(runs_asc) > 1:
197+
for prev, curr in pairwise(runs_asc):
198+
assert curr.created_time >= prev.created_time
199+
200+
# Test iterator with sort by createdTime descending
201+
runs_iter = list(
202+
cognite_client.simulators.runs(
203+
routine_external_ids=[routine_external_id],
204+
sort=SimulationRunsSort(order="desc", property="created_time"),
205+
limit=3,
206+
)
207+
)
208+
209+
if len(runs_iter) > 1:
210+
for prev, curr in pairwise(runs_iter):
211+
assert curr.created_time <= prev.created_time
212+
184213
def test_list_run_data(self, cognite_client: CogniteClient, seed_resource_names: ResourceNames) -> None:
185214
routine_external_id = seed_resource_names.simulator_routine_external_id
186215
created_run = cognite_client.simulators.runs.create(

0 commit comments

Comments
 (0)