Coverage for backend/django/idaes_factory/adapters/property_value_adapter.py: 80%

58 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2026-02-11 21:43 +0000

1import json 

2from core.auxiliary.models.PropertyInfo import PropertyInfo, check_is_except_last 

3from core.auxiliary.models.PropertyValue import PropertyValue, sort_indexes 

4from core.auxiliary.enums.uiEnums import DisplayType 

5from common.config_types import * 

6from core.auxiliary.models.DataCell import DataCell 

7from ..idaes_factory_context import IdaesFactoryContext 

8 

9class _PropertyInfoNotSetException(Exception): 

10 def __init__(self, message: str = ""): 

11 if message == "": 

12 message = "PropertyInfo value not set" 

13 super().__init__(message) 

14 

15 

16# Property info operator 

17def check_fixed(ctx:IdaesFactoryContext, property_info: PropertyInfo, property_value: PropertyValue, is_tear: bool = False) -> bool: 

18 """ 

19 Check that the property is fixed 

20 Raise an error if not, or return False if variables are not required to be fixed 

21 """ 

22 if is_tear and not property_value.is_control_set_point() and not property_value.has_value(): 

23 # recycle guess, allowed to be empty 

24 return False 

25 # Property must be fixed, and have a value 

26 if not property_value.has_value(): 

27 if property_value.is_control_manipulated(): 

28 # this value is a guess variable, and allowed to be empty 

29 return False 

30 indexed_items = [x for x in property_value.indexedItems.all()] 

31 property_values = [x for x in property_info.values.all()] 

32 pv_ii = [[x for x in y.indexedItems.all()] for y in property_values] 

33 # error, property should be fixed and have a value 

34 if ctx.require_variables_fixed: 34 ↛ 35line 34 didn't jump to line 35 because the condition on line 34 was never true

35 raise _PropertyInfoNotSetException(f"Property `{property_info.displayName}` is not set") 

36 else: 

37 # RequireVariablesFixed is a context variable that can be set to False to allow for properties to be unset 

38 # Allow this to pass for testing purposes only. 

39 return False 

40 return True 

41 

42 

43def serialise_property_value(ctx:IdaesFactoryContext, property_info: PropertyInfo, property_value: PropertyValue, is_indexed: bool = True, is_tear: bool = False): 

44 """ 

45 Serialise a property info object 

46 """ 

47 

48 # TODO: add time step handling: get the value at the given time step 

49 match property_info.type: 

50 case DisplayType.dropdown: 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.checkbox: 52 ↛ 53line 52 didn't jump to line 53 because the pattern on line 52 never matched

53 return bool(json.loads(property_value.value)) # return True or False 

54 case DisplayType.numeric_arg: 54 ↛ 55line 54 didn't jump to line 55 because the pattern on line 54 never matched

55 raise NotImplementedError("Dropdown properties are not yet supported in idaes_factory") 

56 case DisplayType.segmented: 56 ↛ 57line 56 didn't jump to line 57 because the pattern on line 56 never matched

57 raise NotImplementedError("Segmented properties are not yet supported in idaes_factory") 

58 case DisplayType.numeric: 58 ↛ 102line 58 didn't jump to line 102 because the pattern on line 58 always matched

59 if is_tear: 

60 # tear properties are disabled, but we still need to serialise the recycle guesses 

61 if not ( 

62 property_info.is_recycle_var() 

63 or property_value.is_control_set_point() 

64 ): 

65 # skip, not enabled 

66 return None 

67 else: 

68 if not property_value.is_enabled() and not property_value.is_control_manipulated(): 

69 # property is disabled (and not a guess), so don't serialise it 

70 return None 

71 # check that the property is fixed, and raise an error if not 

72 if not check_fixed(ctx, property_info, property_value, is_tear): 

73 # variables are not required to be fixed, so don't serialise this property 

74 return None 

75 

76 value = property_value.value 

77 # We are no longer supporting parsing expressions here, becuase that functionality 

78 # is possible with specification and control blocks. 

79 if getattr(property_value, "dataColumn", None) is not None: 

80 if ctx.solve_index is not None: # if index is given for a value from the csv 

81 value = DataCell.objects.get( 

82 data_column = property_value.dataColumn, 

83 data_row = ctx.solve_index, 

84 ).value 

85 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. 85 ↛ 98line 85 didn't jump to line 98 because the condition on line 85 was always true

86 # We want to get all the data cells, and use as many data cells as there are timesteps 

87 # (We are using the CSV data as input data) 

88 # Note: assuming DataCell.objects.all() returns the values in the correct order 

89 value = [i.value for i in DataCell.objects.filter(data_column=property_value.dataColumn).all()] 

90 value = value[0:len(ctx.time_steps)] 

91 return value 

92 

93 elif ctx.is_dynamic() and is_indexed: 

94 return [float(value) for _ in ctx.time_steps] 

95 

96 # we used to use the dynamic results as the input but we aren't doing that any more 

97 # so just return the one value, idaes_service will assume it's constant. 

98 if is_indexed: 

99 return [float(value)] 

100 else: 

101 return float(value) 

102 case _: 

103 raise ValueError(f"Property type {property_info.type} is not supported in idaes_factory")