Coverage for backend/django/idaes_factory/adapters/property_value_adapter.py: 80%
55 statements
« prev ^ index » next coverage.py v7.10.7, created at 2026-05-13 02:47 +0000
« prev ^ index » next coverage.py v7.10.7, created at 2026-05-13 02:47 +0000
1import json
2from core.auxiliary.enums.uiEnums import DisplayType
3from common.config_types import *
5class _PropertyInfoNotSetException(Exception):
6 def __init__(self, message: str = ""):
7 if message == "":
8 message = "PropertyInfo value not set"
9 super().__init__(message)
12# Property info operator
13def check_fixed(ctx, property_info, property_value, is_tear: bool = False) -> bool:
14 """
15 Check that the property is fixed
16 Raise an error if not, or return False if variables are not required to be fixed
17 """
18 if is_tear and not property_value.is_control_set_point() and not property_value.has_value():
19 # recycle guess, allowed to be empty
20 return False
21 # Property must be fixed, and have a value
22 if not property_value.has_value():
23 if property_value.is_control_manipulated():
24 # this value is a guess variable, and allowed to be empty
25 return False
26 indexed_items = [x for x in property_value.indexedItems.all()]
27 property_values = [x for x in property_info.values.all()]
28 pv_ii = [[x for x in y.indexedItems.all()] for y in property_values]
29 # error, property should be fixed and have a value
30 if ctx.require_variables_fixed: 30 ↛ 31line 30 didn't jump to line 31 because the condition on line 30 was never true
31 raise _PropertyInfoNotSetException(f"Property `{property_info.displayName}` is not set")
32 else:
33 # RequireVariablesFixed is a context variable that can be set to False to allow for properties to be unset
34 # Allow this to pass for testing purposes only.
35 return False
36 return True
39def serialise_property_value(ctx, property_info, property_value, is_indexed: bool = True, is_tear: bool = False):
40 """
41 Serialise a property info object
42 """
44 # TODO: add time step handling: get the value at the given time step
45 match property_info.type:
46 case DisplayType.dropdown: 46 ↛ 47line 46 didn't jump to line 47 because the pattern on line 46 never matched
47 raise NotImplementedError("Dropdown properties are not yet supported in idaes_factory")
48 case DisplayType.checkbox: 48 ↛ 49line 48 didn't jump to line 49 because the pattern on line 48 never matched
49 return bool(json.loads(property_value.value)) # return True or False
50 case DisplayType.numeric_arg: 50 ↛ 51line 50 didn't jump to line 51 because the pattern on line 50 never matched
51 raise NotImplementedError("Dropdown properties are not yet supported in idaes_factory")
52 case DisplayType.segmented: 52 ↛ 53line 52 didn't jump to line 53 because the pattern on line 52 never matched
53 raise NotImplementedError("Segmented properties are not yet supported in idaes_factory")
54 case DisplayType.numeric: 54 ↛ 100line 54 didn't jump to line 100 because the pattern on line 54 always matched
55 if is_tear:
56 # tear properties are disabled, but we still need to serialise the recycle guesses
57 if not (
58 property_info.is_recycle_var()
59 or property_value.is_control_set_point()
60 ):
61 # skip, not enabled
62 return None
63 else:
64 if not property_value.is_enabled() and not property_value.is_control_manipulated():
65 # property is disabled (and not a guess), so don't serialise it
66 return None
67 # check that the property is fixed, and raise an error if not
68 if not check_fixed(ctx, property_info, property_value, is_tear):
69 # variables are not required to be fixed, so don't serialise this property
70 return None
72 value = property_value.value
73 # We are no longer supporting parsing expressions here, becuase that functionality
74 # is possible with specification and control blocks.
75 if getattr(property_value, "dataColumn", None) is not None:
76 from core.auxiliary.models.DataCell import DataCell
78 if ctx.solve_index is not None: # if index is given for a value from the csv
79 value = DataCell.objects.get(
80 data_column = property_value.dataColumn,
81 data_row = ctx.solve_index,
82 ).value
83 elif ctx.is_dynamic() and is_indexed: # only use MSS for dynamics if the property is indexed, because otherwise it will be a single value. 83 ↛ 96line 83 didn't jump to line 96 because the condition on line 83 was always true
84 # We want to get all the data cells, and use as many data cells as there are timesteps
85 # (We are using the CSV data as input data)
86 # Note: assuming DataCell.objects.all() returns the values in the correct order
87 value = [i.value for i in DataCell.objects.filter(data_column=property_value.dataColumn).all()]
88 value = value[0:len(ctx.time_steps)]
89 return value
91 elif ctx.is_dynamic() and is_indexed:
92 return [float(value) for _ in ctx.time_steps]
94 # we used to use the dynamic results as the input but we aren't doing that any more
95 # so just return the one value, idaes_service will assume it's constant.
96 if is_indexed:
97 return [float(value)]
98 else:
99 return float(value)
100 case _:
101 raise ValueError(f"Property type {property_info.type} is not supported in idaes_factory")