Skip to content

Commit 0c16785

Browse files
feat: add helper methods to access simulator quantities and units (#2305)
1 parent 2ad8a72 commit 0c16785

3 files changed

Lines changed: 149 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ As of 2025-08-29, changes are grouped as follows
2424
## [Unreleased]
2525
### Added
2626
- [alpha] Support for `created_time` and `simulation_time` filters in `client.simulators.runs.list()` to filter simulation runs by timestamp ranges.
27+
- Added `get_quantities()` and `get_units()` methods to the `Simulator` class for easier access to simulator unit quantities and their units.
2728

2829
## [7.82.1] - 2025-08-28
2930
### Fixed

cognite/client/data_classes/simulators/simulators.py

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,38 @@ def dump(self, camel_case: bool = True) -> dict[str, Any]:
108108

109109
return output
110110

111+
def get_quantities(self) -> list[str]:
112+
"""Get a list of quantity names available for this simulator.
113+
114+
Returns:
115+
list[str]: List of quantity names from the simulator's unit_quantities.
116+
"""
117+
if not self.unit_quantities:
118+
return []
119+
return [quantity.name for quantity in self.unit_quantities]
120+
121+
def get_units(self, quantity: str) -> list[str]:
122+
"""Get a list of unit names for a specific quantity.
123+
124+
Args:
125+
quantity (str): The name of the quantity to get units for.
126+
127+
Returns:
128+
list[str]: List of unit names for the specified quantity.
129+
130+
Raises:
131+
ValueError: If the specified quantity does not exist for this simulator.
132+
"""
133+
if not self.unit_quantities:
134+
raise ValueError(f"Quantity '{quantity}' not found. This simulator has no unit quantities defined.")
135+
136+
for q in self.unit_quantities:
137+
if q.name == quantity:
138+
return [unit.name for unit in q.units]
139+
140+
available_quantities = self.get_quantities()
141+
raise ValueError(f"Quantity '{quantity}' not found. Available quantities: {', '.join(available_quantities)}")
142+
111143

112144
@dataclass
113145
class SimulatorUnitEntry(CogniteObject):
@@ -149,7 +181,9 @@ def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None =
149181

150182
@classmethod
151183
def _load_list(
152-
cls, resource: dict[str, Any] | list[dict[str, Any]], cognite_client: CogniteClient | None = None
184+
cls,
185+
resource: dict[str, Any] | list[dict[str, Any]],
186+
cognite_client: CogniteClient | None = None,
153187
) -> list[SimulatorModelType]:
154188
if isinstance(resource, dict):
155189
return [cls._load(resource, cognite_client)]
@@ -175,7 +209,9 @@ def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None =
175209

176210
@classmethod
177211
def _load_list(
178-
cls, resource: dict[str, Any] | list[dict[str, Any]], cognite_client: CogniteClient | None = None
212+
cls,
213+
resource: dict[str, Any] | list[dict[str, Any]],
214+
cognite_client: CogniteClient | None = None,
179215
) -> list[SimulatorQuantity]:
180216
if isinstance(resource, dict):
181217
return [cls._load(resource, cognite_client)]
@@ -261,7 +297,9 @@ def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None =
261297

262298
@classmethod
263299
def _load_list(
264-
cls, resource: dict[str, Any] | list[dict[str, Any]], cognite_client: CogniteClient | None = None
300+
cls,
301+
resource: dict[str, Any] | list[dict[str, Any]],
302+
cognite_client: CogniteClient | None = None,
265303
) -> list[SimulatorModelDependency]:
266304
if isinstance(resource, dict):
267305
return [cls._load(resource, cognite_client)]
@@ -291,7 +329,9 @@ def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None =
291329

292330
@classmethod
293331
def _load_list(
294-
cls, resource: dict[str, Any] | list[dict[str, Any]], cognite_client: CogniteClient | None = None
332+
cls,
333+
resource: dict[str, Any] | list[dict[str, Any]],
334+
cognite_client: CogniteClient | None = None,
295335
) -> list[SimulatorStep]:
296336
if isinstance(resource, dict):
297337
return [cls._load(resource, cognite_client)]

tests/tests_unit/test_data_classes/test_simulators.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
SimulatorModelDependencyFileId,
55
SimulatorModelRevisionDependency,
66
)
7+
from cognite.client.data_classes.simulators.simulators import (
8+
Simulator,
9+
SimulatorQuantity,
10+
SimulatorUnitEntry,
11+
)
712

813

914
class TestSimulatorModelRevisionDependency:
@@ -28,3 +33,102 @@ def test_load_list(self, input_data):
2833
assert result[0].arguments == {"fieldA": "valueA"}
2934
assert isinstance(result[0].file, SimulatorModelDependencyFileId)
3035
assert result[1].file.id == 2222
36+
37+
38+
class TestSimulator:
39+
@pytest.fixture
40+
def simulator_with_quantities(self):
41+
"""Create a simulator with unit quantities for testing."""
42+
unit_m = SimulatorUnitEntry(label="Meters", name="m")
43+
unit_ft = SimulatorUnitEntry(label="Feet", name="ft")
44+
unit_kg = SimulatorUnitEntry(label="Kilograms", name="kg")
45+
unit_lb = SimulatorUnitEntry(label="Pounds", name="lb")
46+
unit_c = SimulatorUnitEntry(label="Celsius", name="C")
47+
unit_f = SimulatorUnitEntry(label="Fahrenheit", name="F")
48+
49+
quantity_length = SimulatorQuantity(name="length", label="Length", units=[unit_m, unit_ft])
50+
quantity_mass = SimulatorQuantity(name="mass", label="Mass", units=[unit_kg, unit_lb])
51+
quantity_temp = SimulatorQuantity(name="temperature", label="Temperature", units=[unit_c, unit_f])
52+
53+
return Simulator(
54+
external_id="test-simulator",
55+
id=1,
56+
name="Test Simulator",
57+
file_extension_types=[".sim"],
58+
unit_quantities=[quantity_length, quantity_mass, quantity_temp],
59+
)
60+
61+
@pytest.fixture
62+
def simulator_without_quantities(self):
63+
"""Create a simulator without unit quantities for testing."""
64+
return Simulator(
65+
external_id="empty-simulator",
66+
id=2,
67+
name="Empty Simulator",
68+
file_extension_types=[".sim"],
69+
unit_quantities=None,
70+
)
71+
72+
def test_get_quantities_with_data(self, simulator_with_quantities):
73+
"""Test get_quantities returns correct list when quantities exist."""
74+
quantities = simulator_with_quantities.get_quantities()
75+
assert quantities == ["length", "mass", "temperature"]
76+
assert len(quantities) == 3
77+
assert all(isinstance(q, str) for q in quantities)
78+
79+
def test_get_quantities_empty(self, simulator_without_quantities):
80+
"""Test get_quantities returns empty list when no quantities exist."""
81+
quantities = simulator_without_quantities.get_quantities()
82+
assert quantities == []
83+
assert len(quantities) == 0
84+
85+
def test_get_units_valid_quantity(self, simulator_with_quantities):
86+
"""Test get_units returns correct units for valid quantities."""
87+
# Test length units
88+
length_units = simulator_with_quantities.get_units("length")
89+
assert length_units == ["m", "ft"]
90+
assert len(length_units) == 2
91+
92+
# Test mass units
93+
mass_units = simulator_with_quantities.get_units("mass")
94+
assert mass_units == ["kg", "lb"]
95+
assert len(mass_units) == 2
96+
97+
# Test temperature units
98+
temp_units = simulator_with_quantities.get_units("temperature")
99+
assert temp_units == ["C", "F"]
100+
assert len(temp_units) == 2
101+
102+
def test_get_units_invalid_quantity(self, simulator_with_quantities):
103+
"""Test get_units raises ValueError for non-existent quantity."""
104+
with pytest.raises(ValueError) as exc_info:
105+
simulator_with_quantities.get_units("pressure")
106+
107+
error_msg = str(exc_info.value)
108+
assert "Quantity 'pressure' not found" in error_msg
109+
assert "Available quantities: length, mass, temperature" in error_msg
110+
111+
def test_get_units_no_quantities(self, simulator_without_quantities):
112+
"""Test get_units raises ValueError when simulator has no quantities."""
113+
with pytest.raises(ValueError) as exc_info:
114+
simulator_without_quantities.get_units("any_quantity")
115+
116+
error_msg = str(exc_info.value)
117+
assert "Quantity 'any_quantity' not found" in error_msg
118+
assert "This simulator has no unit quantities defined" in error_msg
119+
120+
def test_get_units_empty_units_list(self):
121+
"""Test get_units with quantity that has empty units list."""
122+
empty_quantity = SimulatorQuantity(name="empty", label="Empty Quantity", units=[])
123+
124+
simulator = Simulator(
125+
external_id="test-sim",
126+
id=3,
127+
name="Test",
128+
file_extension_types=[".sim"],
129+
unit_quantities=[empty_quantity],
130+
)
131+
132+
units = simulator.get_units("empty")
133+
assert units == []
134+
assert len(units) == 0

0 commit comments

Comments
 (0)