Coverage for backend/django/Economics/formulas/native_properties/materialize.py: 87%
70 statements
« prev ^ index » next coverage.py v7.10.7, created at 2026-06-23 21:51 +0000
« prev ^ index » next coverage.py v7.10.7, created at 2026-06-23 21:51 +0000
1from __future__ import annotations
3from django.core.exceptions import ObjectDoesNotExist
4from django.db import transaction
6from core.auxiliary.models.PropertyInfo import PropertyInfo
7from core.auxiliary.models.PropertySet import PropertySet
8from core.auxiliary.models.PropertyValue import PropertyValue
9from Economics.formulas.models import EconomicsMetricFormula
10from Economics.formulas.property_state import apply_economics_property_state
11from Economics.studies.models import EconomicsStudy
12from Economics.formulas.native_properties.specs import EconomicsNativePropertySpec, native_property_specs
15def materialize_economics_native_properties(study: EconomicsStudy) -> dict[str, PropertyValue]:
16 """Create or update managed native-property rows for a flowsheet study."""
18 with transaction.atomic():
19 property_set = _native_property_set(study)
20 values: dict[str, PropertyValue] = {}
21 for spec in native_property_specs(study):
22 values[spec.field_key] = _materialize_spec(study=study, property_set=property_set, spec=spec)
23 return values
26def _materialize_spec(
27 *,
28 study: EconomicsStudy,
29 property_set: PropertySet,
30 spec: EconomicsNativePropertySpec,
31) -> PropertyValue:
32 property_info = _native_property_info(study=study, property_set=property_set, spec=spec)
33 value = _single_scalar_value(property_info)
34 _link_native_formula_owner(study=study, spec=spec, property_value=value)
35 apply_economics_property_state(
36 property_info,
37 editable=spec.editable,
38 formula_incomplete=None,
39 )
40 return value
43def _link_native_formula_owner(
44 *,
45 study: EconomicsStudy,
46 spec: EconomicsNativePropertySpec,
47 property_value: PropertyValue,
48) -> None:
49 EconomicsMetricFormula.objects.update_or_create(
50 flowsheet=study.flowsheet,
51 study=study,
52 metric_key=_native_metric_key(spec),
53 defaults={
54 "property_value": property_value,
55 "formula_key": spec.field_key,
56 "unit": property_value.property.unit,
57 },
58 )
61def _native_property_info(
62 *,
63 study: EconomicsStudy,
64 property_set: PropertySet,
65 spec: EconomicsNativePropertySpec,
66) -> PropertyInfo:
67 property_info = _source_owned_native_property_info(study=study, spec=spec)
68 defaults = {
69 "set": property_set,
70 "type": "numeric",
71 "unitType": spec.unit_type,
72 "unit": spec.unit,
73 "displayName": spec.display_name,
74 "index": 0,
75 }
76 if property_info is None:
77 property_info = PropertyInfo.objects.create(
78 flowsheet=study.flowsheet,
79 key=spec.property_key,
80 **defaults,
81 )
82 return property_info
83 changed_fields = []
84 for field_name, value in defaults.items():
85 if getattr(property_info, field_name) != value: 85 ↛ 86line 85 didn't jump to line 86 because the condition on line 85 was never true
86 setattr(property_info, field_name, value)
87 changed_fields.append(field_name)
88 if property_info.key != spec.property_key: 88 ↛ 89line 88 didn't jump to line 89 because the condition on line 88 was never true
89 property_info.key = spec.property_key
90 changed_fields.append("key")
91 if changed_fields: 91 ↛ 92line 91 didn't jump to line 92 because the condition on line 91 was never true
92 property_info.save(update_fields=changed_fields)
93 return property_info
96def _source_owned_native_property_info(
97 *,
98 study: EconomicsStudy,
99 spec: EconomicsNativePropertySpec,
100) -> PropertyInfo | None:
101 property_value = (
102 EconomicsMetricFormula.objects.filter(
103 flowsheet=study.flowsheet,
104 study=study,
105 metric_key=_native_metric_key(spec),
106 property_value__isnull=False,
107 )
108 .select_related("property_value__property")
109 .order_by("pk")
110 .first()
111 )
112 if property_value is None or property_value.property_value is None:
113 return None
114 return property_value.property_value.property
117def _single_scalar_value(property_info: PropertyInfo) -> PropertyValue:
118 values = list(property_info.values.order_by("pk"))
119 value = values[0] if values else None
120 for duplicate in values[1:]: 120 ↛ 121line 120 didn't jump to line 121 because the loop on line 120 never started
121 duplicate.delete()
122 if value is None:
123 value = PropertyValue.objects.create(
124 flowsheet=property_info.flowsheet,
125 property=property_info,
126 value=None,
127 displayValue=None,
128 enabled=True,
129 )
130 return value
133def _native_property_set(study: EconomicsStudy) -> PropertySet:
134 root_grouping = getattr(study.flowsheet, "rootGrouping", None)
135 try:
136 root_object = getattr(root_grouping, "simulationObject", None)
137 except ObjectDoesNotExist:
138 root_object = None
139 if root_object is not None:
140 property_set, _ = PropertySet.objects.get_or_create(
141 flowsheet=study.flowsheet,
142 simulationObject=root_object,
143 )
144 return property_set
145 property_set = PropertySet.objects.filter(flowsheet=study.flowsheet, simulationObject__isnull=True).order_by("pk").first()
146 if property_set is not None:
147 return property_set
148 return PropertySet.objects.create(flowsheet=study.flowsheet, simulationObject=None)
151def _native_metric_key(spec: EconomicsNativePropertySpec) -> str:
152 return spec.result_metric_key or spec.field_key