zepben.ewb 1.0.0b8__py3-none-any.whl → 1.0.0b10__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. zepben/ewb/database/sqlite/common/base_cim_reader.py +7 -7
  2. zepben/ewb/database/sqlite/common/base_database_writer.py +2 -2
  3. zepben/ewb/database/sqlite/network/network_cim_reader.py +20 -20
  4. zepben/ewb/database/sqlite/network/network_database_reader.py +4 -2
  5. zepben/ewb/database/sqlite/tables/iec61968/common/table_documents.py +5 -5
  6. zepben/ewb/database/sqlite/tables/iec61968/common/table_street_addresses.py +1 -1
  7. zepben/ewb/database/sqlite/tables/iec61968/infiec61968/infassets/table_poles.py +1 -1
  8. zepben/ewb/database/sqlite/tables/iec61970/base/core/table_identified_objects.py +3 -3
  9. zepben/ewb/database/sqlite/tables/iec61970/base/core/table_power_system_resources.py +1 -1
  10. zepben/ewb/database/sqlite/tables/iec61970/base/meas/table_analogs.py +1 -1
  11. zepben/ewb/database/sqlite/tables/iec61970/base/wires/table_energy_consumers.py +1 -1
  12. zepben/ewb/database/sqlite/tables/iec61970/base/wires/table_energy_sources.py +1 -1
  13. zepben/ewb/database/sqlite/tables/iec61970/base/wires/table_regulating_cond_eq.py +1 -1
  14. zepben/ewb/database/sqlite/tables/iec61970/base/wires/table_shunt_compensators.py +1 -1
  15. zepben/ewb/database/sqlite/tables/iec61970/base/wires/table_tap_changers.py +1 -1
  16. zepben/ewb/database/sqlite/tables/iec61970/base/wires/table_transformer_ends.py +1 -1
  17. zepben/ewb/model/cim/iec61968/common/document.py +5 -5
  18. zepben/ewb/model/cim/iec61968/common/street_address.py +2 -2
  19. zepben/ewb/model/cim/iec61968/common/street_detail.py +8 -7
  20. zepben/ewb/model/cim/iec61968/infiec61968/infassets/pole.py +1 -1
  21. zepben/ewb/model/cim/iec61968/metering/meter.py +4 -2
  22. zepben/ewb/model/cim/iec61968/metering/usage_point.py +1 -1
  23. zepben/ewb/model/cim/iec61970/base/core/curve.py +2 -1
  24. zepben/ewb/model/cim/iec61970/base/core/identified_object.py +8 -3
  25. zepben/ewb/model/cim/iec61970/base/core/name_type.py +2 -2
  26. zepben/ewb/model/cim/iec61970/base/core/power_system_resource.py +2 -2
  27. zepben/ewb/model/cim/iec61970/base/meas/analog.py +3 -1
  28. zepben/ewb/model/cim/iec61970/base/wires/energy_consumer.py +1 -1
  29. zepben/ewb/model/cim/iec61970/base/wires/energy_source.py +1 -1
  30. zepben/ewb/model/cim/iec61970/base/wires/regulating_cond_eq.py +1 -1
  31. zepben/ewb/model/cim/iec61970/base/wires/shunt_compensator.py +1 -1
  32. zepben/ewb/model/cim/iec61970/base/wires/synchronous_machine.py +1 -1
  33. zepben/ewb/model/cim/iec61970/base/wires/tap_changer.py +1 -1
  34. zepben/ewb/model/cim/iec61970/base/wires/transformer_end.py +1 -1
  35. zepben/ewb/model/cim/iec61970/base/wires/transformer_star_impedance.py +4 -4
  36. zepben/ewb/services/common/translator/base_cim2proto.py +21 -9
  37. zepben/ewb/services/common/translator/base_proto2cim.py +13 -8
  38. zepben/ewb/services/customer/translator/customer_cim2proto.py +10 -10
  39. zepben/ewb/services/customer/translator/customer_proto2cim.py +9 -9
  40. zepben/ewb/services/diagram/translator/diagram_cim2proto.py +8 -8
  41. zepben/ewb/services/diagram/translator/diagram_proto2cim.py +8 -8
  42. zepben/ewb/services/network/tracing/networktrace/network_trace.py +2 -19
  43. zepben/ewb/services/network/tracing/networktrace/network_trace_action_type.py +2 -2
  44. zepben/ewb/services/network/tracing/networktrace/network_trace_step.py +4 -1
  45. zepben/ewb/services/network/tracing/phases/phase_inferrer.py +2 -2
  46. zepben/ewb/services/network/translator/network_cim2proto.py +451 -322
  47. zepben/ewb/services/network/translator/network_proto2cim.py +305 -287
  48. {zepben_ewb-1.0.0b8.dist-info → zepben_ewb-1.0.0b10.dist-info}/METADATA +3 -4
  49. {zepben_ewb-1.0.0b8.dist-info → zepben_ewb-1.0.0b10.dist-info}/RECORD +52 -52
  50. {zepben_ewb-1.0.0b8.dist-info → zepben_ewb-1.0.0b10.dist-info}/WHEEL +0 -0
  51. {zepben_ewb-1.0.0b8.dist-info → zepben_ewb-1.0.0b10.dist-info}/licenses/LICENSE +0 -0
  52. {zepben_ewb-1.0.0b8.dist-info → zepben_ewb-1.0.0b10.dist-info}/top_level.txt +0 -0
@@ -53,12 +53,12 @@ class BaseCimReader(ABC):
53
53
  :return: True if the `Document` was successfully read from the database and added to the service.
54
54
  :raises SQLException: For any errors encountered reading from the database.
55
55
  """
56
- document.title = result_set.get_string(table.title.query_index, on_none="")
56
+ document.title = result_set.get_string(table.title.query_index, on_none=None)
57
57
  document.created_date_time = result_set.get_instant(table.created_date_time.query_index, on_none=None)
58
- document.author_name = result_set.get_string(table.author_name.query_index, on_none="")
59
- document.type = result_set.get_string(table.type.query_index, on_none="")
60
- document.status = result_set.get_string(table.status.query_index, on_none="")
61
- document.comment = result_set.get_string(table.comment.query_index, on_none="")
58
+ document.author_name = result_set.get_string(table.author_name.query_index, on_none=None)
59
+ document.type = result_set.get_string(table.type.query_index, on_none=None)
60
+ document.status = result_set.get_string(table.status.query_index, on_none=None)
61
+ document.comment = result_set.get_string(table.comment.query_index, on_none=None)
62
62
 
63
63
  return self._load_identified_object(document, table, result_set)
64
64
 
@@ -111,8 +111,8 @@ class BaseCimReader(ABC):
111
111
  :return: True if the `IdentifiedObject` was successfully read from the database and added to the service.
112
112
  :raises SQLException: For any errors encountered reading from the database.
113
113
  """
114
- identified_object.name = result_set.get_string(table.name_.query_index, on_none="")
115
- identified_object.description = result_set.get_string(table.description.query_index, on_none="")
114
+ identified_object.name = result_set.get_string(table.name_.query_index, on_none=None)
115
+ identified_object.description = result_set.get_string(table.description.query_index, on_none=None)
116
116
  # Currently unused
117
117
  # identified_object.num_diagram_objects = result_set.get_int(table.num_diagram_objects.query_index)
118
118
 
@@ -11,7 +11,7 @@ from abc import ABC
11
11
  from contextlib import closing
12
12
  from pathlib import Path
13
13
  from sqlite3 import Connection, Cursor, OperationalError
14
- from typing import Callable, Union
14
+ from typing import Callable, Union, Optional
15
15
 
16
16
  from zepben.ewb.database.sqlite.common.base_database_tables import BaseDatabaseTables
17
17
  from zepben.ewb.database.sqlite.common.base_service_writer import BaseServiceWriter
@@ -66,7 +66,7 @@ class BaseDatabaseWriter(ABC):
66
66
  Provider of the connection to the specified database.
67
67
  """
68
68
 
69
- self._save_connection: Connection
69
+ self._save_connection: Optional[Connection] = None
70
70
  self._has_been_used: bool = False
71
71
 
72
72
  def save(self) -> bool:
@@ -1070,22 +1070,22 @@ class NetworkCimReader(BaseCimReader):
1070
1070
 
1071
1071
  def _load_street_address(self, table: TableStreetAddresses, result_set: ResultSet) -> StreetAddress:
1072
1072
  return StreetAddress(
1073
- result_set.get_string(table.postal_code.query_index, on_none=""),
1073
+ result_set.get_string(table.postal_code.query_index, on_none=None),
1074
1074
  self._load_town_detail(table, result_set),
1075
- result_set.get_string(table.po_box.query_index, on_none=""),
1075
+ result_set.get_string(table.po_box.query_index, on_none=None),
1076
1076
  self._load_street_detail(table, result_set)
1077
1077
  )
1078
1078
 
1079
1079
  @staticmethod
1080
1080
  def _load_street_detail(table: TableStreetAddresses, result_set: ResultSet) -> Optional[StreetDetail]:
1081
1081
  sd = StreetDetail(
1082
- result_set.get_string(table.building_name.query_index, on_none=""),
1083
- result_set.get_string(table.floor_identification.query_index, on_none=""),
1084
- result_set.get_string(table.street_name.query_index, on_none=""),
1085
- result_set.get_string(table.number.query_index, on_none=""),
1086
- result_set.get_string(table.suite_number.query_index, on_none=""),
1087
- result_set.get_string(table.type.query_index, on_none=""),
1088
- result_set.get_string(table.display_address.query_index, on_none="")
1082
+ result_set.get_string(table.building_name.query_index, on_none=None),
1083
+ result_set.get_string(table.floor_identification.query_index, on_none=None),
1084
+ result_set.get_string(table.street_name.query_index, on_none=None),
1085
+ result_set.get_string(table.number.query_index, on_none=None),
1086
+ result_set.get_string(table.suite_number.query_index, on_none=None),
1087
+ result_set.get_string(table.type.query_index, on_none=None),
1088
+ result_set.get_string(table.display_address.query_index, on_none=None)
1089
1089
  )
1090
1090
 
1091
1091
  return sd if not sd.all_fields_empty() else None
@@ -1178,7 +1178,7 @@ class NetworkCimReader(BaseCimReader):
1178
1178
  """
1179
1179
  pole = Pole(mrid=set_identifier(result_set.get_string(table.mrid.query_index)))
1180
1180
 
1181
- pole.classification = result_set.get_string(table.classification.query_index, on_none="")
1181
+ pole.classification = result_set.get_string(table.classification.query_index, on_none=None)
1182
1182
 
1183
1183
  return self._load_structure(pole, table, result_set) and self._add_or_throw(pole)
1184
1184
 
@@ -1232,7 +1232,7 @@ class NetworkCimReader(BaseCimReader):
1232
1232
  result_set.get_string(table.location_mrid.query_index, on_none=None),
1233
1233
  Location
1234
1234
  )
1235
- usage_point.is_virtual = result_set.get_boolean(table.is_virtual.query_index)
1235
+ usage_point.is_virtual = result_set.get_boolean(table.is_virtual.query_index, on_none=None)
1236
1236
  usage_point.connection_category = result_set.get_string(table.connection_category.query_index, on_none=None)
1237
1237
  usage_point.rated_power = result_set.get_int(table.rated_power.query_index, on_none=None)
1238
1238
  usage_point.approved_inverter_capacity = result_set.get_int(table.approved_inverter_capacity.query_index, on_none=None)
@@ -1472,7 +1472,7 @@ class NetworkCimReader(BaseCimReader):
1472
1472
  result_set.get_string(table.location_mrid.query_index, on_none=None),
1473
1473
  Location
1474
1474
  )
1475
- power_system_resource.num_controls = result_set.get_int(table.num_controls.query_index)
1475
+ power_system_resource.num_controls = result_set.get_int(table.num_controls.query_index, on_none=None)
1476
1476
 
1477
1477
  return self._load_identified_object(power_system_resource, table, result_set)
1478
1478
 
@@ -1686,7 +1686,7 @@ class NetworkCimReader(BaseCimReader):
1686
1686
  """
1687
1687
  meas = Analog(mrid=set_identifier(result_set.get_string(table.mrid.query_index)))
1688
1688
 
1689
- meas.positive_flow_in = result_set.get_boolean(table.positive_flow_in.query_index)
1689
+ meas.positive_flow_in = result_set.get_boolean(table.positive_flow_in.query_index, on_none=None)
1690
1690
 
1691
1691
  return self._load_measurement(meas, table, result_set) and self._add_or_throw(meas)
1692
1692
 
@@ -1956,7 +1956,7 @@ class NetworkCimReader(BaseCimReader):
1956
1956
  energy_consumer = EnergyConsumer(mrid=set_identifier(result_set.get_string(table.mrid.query_index)))
1957
1957
 
1958
1958
  energy_consumer.customer_count = result_set.get_int(table.customer_count.query_index, on_none=None)
1959
- energy_consumer.grounded = result_set.get_boolean(table.grounded.query_index)
1959
+ energy_consumer.grounded = result_set.get_boolean(table.grounded.query_index, on_none=None)
1960
1960
  energy_consumer.p = result_set.get_float(table.p.query_index, on_none=None)
1961
1961
  energy_consumer.q = result_set.get_float(table.q.query_index, on_none=None)
1962
1962
  energy_consumer.p_fixed = result_set.get_float(table.p_fixed.query_index, on_none=None)
@@ -2018,7 +2018,7 @@ class NetworkCimReader(BaseCimReader):
2018
2018
  energy_source.x = result_set.get_float(table.x.query_index, on_none=None)
2019
2019
  energy_source.x0 = result_set.get_float(table.x0.query_index, on_none=None)
2020
2020
  energy_source.xn = result_set.get_float(table.xn.query_index, on_none=None)
2021
- energy_source.is_external_grid = result_set.get_boolean(table.is_external_grid.query_index)
2021
+ energy_source.is_external_grid = result_set.get_boolean(table.is_external_grid.query_index, on_none=None)
2022
2022
  energy_source.r_min = result_set.get_float(table.r_min.query_index, on_none=None)
2023
2023
  energy_source.rn_min = result_set.get_float(table.rn_min.query_index, on_none=None)
2024
2024
  energy_source.r0_min = result_set.get_float(table.r0_min.query_index, on_none=None)
@@ -2488,7 +2488,7 @@ class NetworkCimReader(BaseCimReader):
2488
2488
  return self._load_protected_switch(recloser, table, result_set) and self._add_or_throw(recloser)
2489
2489
 
2490
2490
  def _load_regulating_cond_eq(self, regulating_cond_eq: RegulatingCondEq, table: TableRegulatingCondEq, result_set: ResultSet) -> bool:
2491
- regulating_cond_eq.control_enabled = result_set.get_boolean(table.control_enabled.query_index)
2491
+ regulating_cond_eq.control_enabled = result_set.get_boolean(table.control_enabled.query_index, on_none=None)
2492
2492
  # We use a resolver here because there is an ordering conflict between terminals, RegulatingCondEq, and RegulatingControls
2493
2493
  # We check this resolver has actually been resolved in the postLoad of the database read and throw there if it hasn't.
2494
2494
  self._service.resolve_or_defer_reference(
@@ -2556,7 +2556,7 @@ class NetworkCimReader(BaseCimReader):
2556
2556
  ShuntCompensatorInfo
2557
2557
  )
2558
2558
 
2559
- shunt_compensator.grounded = result_set.get_boolean(table.grounded.query_index)
2559
+ shunt_compensator.grounded = result_set.get_boolean(table.grounded.query_index, on_none=None)
2560
2560
  shunt_compensator.nom_u = result_set.get_int(table.nom_u.query_index, on_none=None)
2561
2561
  shunt_compensator.phase_connection = PhaseShuntConnectionKind[result_set.get_string(table.phase_connection.query_index)]
2562
2562
  shunt_compensator.sections = result_set.get_float(table.sections.query_index, on_none=None)
@@ -2610,7 +2610,7 @@ class NetworkCimReader(BaseCimReader):
2610
2610
 
2611
2611
  synchronous_machine.base_q = result_set.get_float(table.base_q.query_index, on_none=None)
2612
2612
  synchronous_machine.condenser_p = result_set.get_int(table.condenser_p.query_index, on_none=None)
2613
- synchronous_machine.earthing = result_set.get_boolean(table.earthing.query_index)
2613
+ synchronous_machine.earthing = result_set.get_boolean(table.earthing.query_index, on_none=None)
2614
2614
  synchronous_machine.earthing_star_point_r = result_set.get_float(table.earthing_star_point_r.query_index, on_none=None)
2615
2615
  synchronous_machine.earthing_star_point_x = result_set.get_float(table.earthing_star_point_x.query_index, on_none=None)
2616
2616
  synchronous_machine.ikk = result_set.get_float(table.ikk.query_index, on_none=None)
@@ -2633,7 +2633,7 @@ class NetworkCimReader(BaseCimReader):
2633
2633
  return self._load_rotating_machine(synchronous_machine, table, result_set) and self._add_or_throw(synchronous_machine)
2634
2634
 
2635
2635
  def _load_tap_changer(self, tap_changer: TapChanger, table: TableTapChangers, result_set: ResultSet) -> bool:
2636
- tap_changer.control_enabled = result_set.get_boolean(table.control_enabled.query_index)
2636
+ tap_changer.control_enabled = result_set.get_boolean(table.control_enabled.query_index, on_none=None)
2637
2637
  tap_changer.high_step = result_set.get_int(table.high_step.query_index, on_none=None)
2638
2638
  tap_changer.low_step = result_set.get_int(table.low_step.query_index, on_none=None)
2639
2639
  tap_changer.neutral_step = result_set.get_int(table.neutral_step.query_index, on_none=None)
@@ -2681,7 +2681,7 @@ class NetworkCimReader(BaseCimReader):
2681
2681
  result_set.get_string(table.base_voltage_mrid.query_index, on_none=None),
2682
2682
  BaseVoltage
2683
2683
  )
2684
- transformer_end.grounded = result_set.get_boolean(table.grounded.query_index)
2684
+ transformer_end.grounded = result_set.get_boolean(table.grounded.query_index, on_none=None)
2685
2685
  transformer_end.r_ground = result_set.get_float(table.r_ground.query_index, on_none=None)
2686
2686
  transformer_end.x_ground = result_set.get_float(table.x_ground.query_index, on_none=None)
2687
2687
  transformer_end.star_impedance = self._ensure_get(
@@ -154,9 +154,11 @@ class NetworkDatabaseReader(BaseDatabaseReader):
154
154
  feeder_start_points = set(map(head_conducting_equipment_mrid, self.service.objects(Feeder)))
155
155
 
156
156
  def has_been_assigned_to_feeder(energy_source: EnergySource) -> bool:
157
- return energy_source.is_external_grid \
158
- and self._is_on_feeder(energy_source) \
157
+ return (
158
+ energy_source.is_external_grid
159
+ and self._is_on_feeder(energy_source)
159
160
  and feeder_start_points.isdisjoint({it.to_equip.mrid for it in connected_equipment(energy_source) if it.to_equip})
161
+ )
160
162
 
161
163
  for es in self.service.objects(EnergySource):
162
164
  if has_been_assigned_to_feeder(es):
@@ -15,9 +15,9 @@ class TableDocuments(TableIdentifiedObjects, ABC):
15
15
 
16
16
  def __init__(self):
17
17
  super().__init__()
18
- self.title: Column = self._create_column("title", "TEXT", Nullable.NOT_NULL)
18
+ self.title: Column = self._create_column("title", "TEXT", Nullable.NULL)
19
19
  self.created_date_time: Column = self._create_column("created_date_time", "TEXT", Nullable.NULL)
20
- self.author_name: Column = self._create_column("author_name", "TEXT", Nullable.NOT_NULL)
21
- self.type: Column = self._create_column("type", "TEXT", Nullable.NOT_NULL)
22
- self.status: Column = self._create_column("status", "TEXT", Nullable.NOT_NULL)
23
- self.comment: Column = self._create_column("comment", "TEXT", Nullable.NOT_NULL)
20
+ self.author_name: Column = self._create_column("author_name", "TEXT", Nullable.NULL)
21
+ self.type: Column = self._create_column("type", "TEXT", Nullable.NULL)
22
+ self.status: Column = self._create_column("status", "TEXT", Nullable.NULL)
23
+ self.comment: Column = self._create_column("comment", "TEXT", Nullable.NULL)
@@ -15,7 +15,7 @@ class TableStreetAddresses(TableTownDetails, ABC):
15
15
 
16
16
  def __init__(self):
17
17
  super().__init__()
18
- self.postal_code: Column = self._create_column("postal_code", "TEXT", Nullable.NOT_NULL)
18
+ self.postal_code: Column = self._create_column("postal_code", "TEXT", Nullable.NULL)
19
19
  self.po_box: Column = self._create_column("po_box", "TEXT", Nullable.NULL)
20
20
  self.building_name: Column = self._create_column("building_name", "TEXT", Nullable.NULL)
21
21
  self.floor_identification: Column = self._create_column("floor_identification", "TEXT", Nullable.NULL)
@@ -13,7 +13,7 @@ class TablePoles(TableStructures):
13
13
 
14
14
  def __init__(self):
15
15
  super().__init__()
16
- self.classification: Column = self._create_column("classification", "TEXT", Nullable.NOT_NULL)
16
+ self.classification: Column = self._create_column("classification", "TEXT", Nullable.NULL)
17
17
 
18
18
  @property
19
19
  def name(self) -> str:
@@ -16,9 +16,9 @@ class TableIdentifiedObjects(SqliteTable, ABC):
16
16
 
17
17
  def __init__(self):
18
18
  self.mrid: Column = self._create_column("mrid", "TEXT", Nullable.NOT_NULL)
19
- self.name_: Column = self._create_column("name", "TEXT", Nullable.NOT_NULL)
20
- self.description: Column = self._create_column("description", "TEXT", Nullable.NOT_NULL)
21
- self.num_diagram_objects: Column = self._create_column("num_diagram_objects", "INTEGER", Nullable.NOT_NULL)
19
+ self.name_: Column = self._create_column("name", "TEXT", Nullable.NULL)
20
+ self.description: Column = self._create_column("description", "TEXT", Nullable.NULL)
21
+ self.num_diagram_objects: Column = self._create_column("num_diagram_objects", "INTEGER", Nullable.NULL)
22
22
 
23
23
  @property
24
24
  def unique_index_columns(self) -> Generator[List[Column], None, None]:
@@ -16,4 +16,4 @@ class TablePowerSystemResources(TableIdentifiedObjects, ABC):
16
16
  def __init__(self):
17
17
  super().__init__()
18
18
  self.location_mrid: Column = self._create_column("location_mrid", "TEXT", Nullable.NULL)
19
- self.num_controls: Column = self._create_column("num_controls", "INTEGER", Nullable.NOT_NULL)
19
+ self.num_controls: Column = self._create_column("num_controls", "INTEGER", Nullable.NULL)
@@ -13,7 +13,7 @@ class TableAnalogs(TableMeasurements):
13
13
 
14
14
  def __init__(self):
15
15
  super().__init__()
16
- self.positive_flow_in: Column = self._create_column("positive_flow_in", "BOOLEAN", Nullable.NOT_NULL)
16
+ self.positive_flow_in: Column = self._create_column("positive_flow_in", "BOOLEAN", Nullable.NULL)
17
17
 
18
18
  @property
19
19
  def name(self) -> str:
@@ -14,7 +14,7 @@ class TableEnergyConsumers(TableEnergyConnections):
14
14
  def __init__(self):
15
15
  super().__init__()
16
16
  self.customer_count: Column = self._create_column("customer_count", "INTEGER", Nullable.NULL)
17
- self.grounded: Column = self._create_column("grounded", "BOOLEAN", Nullable.NOT_NULL)
17
+ self.grounded: Column = self._create_column("grounded", "BOOLEAN", Nullable.NULL)
18
18
  self.p: Column = self._create_column("p", "NUMBER", Nullable.NULL)
19
19
  self.q: Column = self._create_column("q", "NUMBER", Nullable.NULL)
20
20
  self.p_fixed: Column = self._create_column("p_fixed", "NUMBER", Nullable.NULL)
@@ -25,7 +25,7 @@ class TableEnergySources(TableEnergyConnections):
25
25
  self.x: Column = self._create_column("x", "NUMBER", Nullable.NULL)
26
26
  self.x0: Column = self._create_column("x0", "NUMBER", Nullable.NULL)
27
27
  self.xn: Column = self._create_column("xn", "NUMBER", Nullable.NULL)
28
- self.is_external_grid: Column = self._create_column("is_external_grid", "BOOLEAN", Nullable.NOT_NULL)
28
+ self.is_external_grid: Column = self._create_column("is_external_grid", "BOOLEAN", Nullable.NULL)
29
29
  self.r_min: Column = self._create_column("r_min", "NUMBER", Nullable.NULL)
30
30
  self.rn_min: Column = self._create_column("rn_min", "NUMBER", Nullable.NULL)
31
31
  self.r0_min: Column = self._create_column("r0_min", "NUMBER", Nullable.NULL)
@@ -15,5 +15,5 @@ class TableRegulatingCondEq(TableEnergyConnections, ABC):
15
15
 
16
16
  def __init__(self):
17
17
  super().__init__()
18
- self.control_enabled: Column = self._create_column("control_enabled", "BOOLEAN", Nullable.NOT_NULL)
18
+ self.control_enabled: Column = self._create_column("control_enabled", "BOOLEAN", Nullable.NULL)
19
19
  self.regulating_control_mrid: Column = self._create_column("regulating_control_mrid", "TEXT", Nullable.NULL)
@@ -16,7 +16,7 @@ class TableShuntCompensators(TableRegulatingCondEq, ABC):
16
16
  def __init__(self):
17
17
  super().__init__()
18
18
  self.shunt_compensator_info_mrid: Column = self._create_column("shunt_compensator_info_mrid", "TEXT", Nullable.NULL)
19
- self.grounded: Column = self._create_column("grounded", "BOOLEAN", Nullable.NOT_NULL)
19
+ self.grounded: Column = self._create_column("grounded", "BOOLEAN", Nullable.NULL)
20
20
  self.nom_u: Column = self._create_column("nom_u", "INTEGER", Nullable.NULL)
21
21
  self.phase_connection: Column = self._create_column("phase_connection", "TEXT", Nullable.NOT_NULL)
22
22
  self.sections: Column = self._create_column("sections", "NUMBER", Nullable.NULL)
@@ -15,7 +15,7 @@ class TableTapChangers(TablePowerSystemResources, ABC):
15
15
 
16
16
  def __init__(self):
17
17
  super().__init__()
18
- self.control_enabled: Column = self._create_column("control_enabled", "BOOLEAN", Nullable.NOT_NULL)
18
+ self.control_enabled: Column = self._create_column("control_enabled", "BOOLEAN", Nullable.NULL)
19
19
  self.high_step: Column = self._create_column("high_step", "INTEGER", Nullable.NULL)
20
20
  self.low_step: Column = self._create_column("low_step", "INTEGER", Nullable.NULL)
21
21
  self.neutral_step: Column = self._create_column("neutral_step", "INTEGER", Nullable.NULL)
@@ -19,7 +19,7 @@ class TableTransformerEnds(TableIdentifiedObjects, ABC):
19
19
  self.end_number: Column = self._create_column("end_number", "INTEGER", Nullable.NOT_NULL)
20
20
  self.terminal_mrid: Column = self._create_column("terminal_mrid", "TEXT", Nullable.NULL)
21
21
  self.base_voltage_mrid: Column = self._create_column("base_voltage_mrid", "TEXT", Nullable.NULL)
22
- self.grounded: Column = self._create_column("grounded", "BOOLEAN", Nullable.NOT_NULL)
22
+ self.grounded: Column = self._create_column("grounded", "BOOLEAN", Nullable.NULL)
23
23
  self.r_ground: Column = self._create_column("r_ground", "NUMBER", Nullable.NULL)
24
24
  self.x_ground: Column = self._create_column("x_ground", "NUMBER", Nullable.NULL)
25
25
  self.star_impedance_mrid: Column = self._create_column("star_impedance_mrid", "TEXT", Nullable.NULL)
@@ -16,21 +16,21 @@ class Document(IdentifiedObject):
16
16
  Parent class for different groupings of information collected and managed as a part of a business process.
17
17
  It will frequently contain references to other objects, such as assets, people and power system resources.
18
18
  """
19
- title: str = ""
19
+ title: Optional[str] = None
20
20
  """Document title."""
21
21
 
22
22
  created_date_time: Optional[datetime] = None
23
23
  """Date and time that this document was created."""
24
24
 
25
- author_name: str = ""
25
+ author_name: Optional[str] = None
26
26
  """Name of the author of this document."""
27
27
 
28
- type: str = ""
28
+ type: Optional[str] = None
29
29
  """Utility-specific classification of this document, according to its corporate standards, practices,
30
30
  and existing IT systems (e.g., for management of assets, maintenance, work, outage, customers, etc.)."""
31
31
 
32
- status: str = ""
32
+ status: Optional[str] = None
33
33
  """Status of subject matter (e.g., Agreement, Work) this document represents."""
34
34
 
35
- comment: str = ""
35
+ comment: Optional[str] = None
36
36
  """Free text comment"""
@@ -18,11 +18,11 @@ class StreetAddress(object):
18
18
  General purpose street and postal address information.
19
19
  """
20
20
 
21
- postal_code: str = ""
21
+ postal_code: Optional[str] = None
22
22
  """Postal code for the address."""
23
23
  town_detail: Optional[TownDetail] = None
24
24
  """Optional `TownDetail` for this address."""
25
- po_box: str = ""
25
+ po_box: Optional[str] = None
26
26
  """Post office box for the address."""
27
27
  street_detail: Optional[StreetDetail] = None
28
28
  """Optional `StreetDetail` for this address."""
@@ -6,6 +6,7 @@
6
6
  __all__ = ["StreetDetail"]
7
7
 
8
8
  from dataclasses import dataclass
9
+ from typing import Optional
9
10
 
10
11
 
11
12
  @dataclass
@@ -14,22 +15,22 @@ class StreetDetail(object):
14
15
  Street details, in the context of address.
15
16
  """
16
17
 
17
- building_name: str = ""
18
+ building_name: Optional[str] = None
18
19
  """
19
20
  (if applicable) In certain cases the physical location of the place of interest does not have a direct point of entry from the street,
20
21
  but may be located inside a larger structure such as a building, complex, office block, apartment, etc.
21
22
  """
22
- floor_identification: str = ""
23
+ floor_identification: Optional[str] = None
23
24
  """The identification by name or number, expressed as text, of the floor in the building as part of this address."""
24
- name: str = ""
25
+ name: Optional[str] = None
25
26
  """Name of the street."""
26
- number: str = ""
27
+ number: Optional[str] = None
27
28
  """Designator of the specific location on the street."""
28
- suite_number: str = ""
29
+ suite_number: Optional[str] = None
29
30
  """Number of the apartment or suite."""
30
- type: str = ""
31
+ type: Optional[str] = None
31
32
  """Type of street. Examples include: street, circle, boulevard, avenue, road, drive, etc."""
32
- display_address: str = ""
33
+ display_address: Optional[str] = None
33
34
  """The address as it should be displayed to a user."""
34
35
 
35
36
  def all_fields_empty(self):
@@ -19,7 +19,7 @@ if TYPE_CHECKING:
19
19
  class Pole(Structure):
20
20
  """A Pole Asset"""
21
21
 
22
- classification: str = ""
22
+ classification: Optional[str] = None
23
23
  """Pole class: 1, 2, 3, 4, 5, 6, 7, H1, H2, Other, Unknown."""
24
24
 
25
25
  _streetlights: Optional[List[Streetlight]] = None
@@ -5,6 +5,8 @@
5
5
 
6
6
  __all__ = ["Meter"]
7
7
 
8
+ from typing import Optional
9
+
8
10
  from zepben.ewb.model.cim.iec61968.metering.end_device import EndDevice
9
11
 
10
12
 
@@ -14,12 +16,12 @@ class Meter(EndDevice):
14
16
  """
15
17
 
16
18
  @property
17
- def company_meter_id(self):
19
+ def company_meter_id(self) -> Optional[str]:
18
20
  """ Returns this `Meter`s ID. Currently stored in `IdentifiedObject.name` """
19
21
  return self.name
20
22
 
21
23
  @company_meter_id.setter
22
- def company_meter_id(self, meter_id):
24
+ def company_meter_id(self, meter_id: Optional[str]):
23
25
  """
24
26
  `meter_id` The ID to set for this Meter. Will use `IdentifiedObject.name` as a backing field.
25
27
  """
@@ -28,7 +28,7 @@ class UsagePoint(IdentifiedObject):
28
28
  usage_point_location: Optional[Location] = None
29
29
  """Service `zepben.ewb.model.cim.iec61968.common.location.Location` where the service delivered by this `UsagePoint` is consumed."""
30
30
 
31
- is_virtual: bool = False
31
+ is_virtual: Optional[bool] = None
32
32
  """
33
33
  If true, this usage point is virtual, i.e., no physical location exists in the network where a meter could be located to
34
34
  collect the meter readings. For example, one may define a virtual usage point to serve as an aggregation of usage for all
@@ -76,7 +76,8 @@ class Curve(IdentifiedObject):
76
76
  require(all([it.x_value != x for it in self.data]),
77
77
  lambda: f"Unable to add datapoint to {self}. x_value {x} is invalid, as data with same x_value already exist in this Curve.")
78
78
 
79
- self._data = self._data or []
79
+ if self._data is None:
80
+ self._data = []
80
81
  self._data.append(CurveData(x, y1, y2, y3))
81
82
  self._data.sort(key=lambda it: it.x_value)
82
83
 
@@ -34,14 +34,16 @@ class IdentifiedObject(object, metaclass=ABCMeta):
34
34
  """Master resource identifier issued by a model authority. The mRID is unique within an exchange context.
35
35
  Global uniqueness is easily achieved by using a UUID, as specified in RFC 4122, for the mRID. The use of UUID is strongly recommended."""
36
36
 
37
- name: str = ""
37
+ name: Optional[str] = None
38
38
  """The name is any free human readable and possibly non unique text naming the object."""
39
39
 
40
- description: str = ""
40
+ description: Optional[str] = None
41
41
  """a free human readable text describing or naming the object. It may be non unique and may not correlate to a naming hierarchy."""
42
42
 
43
43
  _names: Optional[List[Name]] = None
44
44
 
45
+ # TODO: Missing num_diagram_objects: int = None def has_diagram_objects(self): return (self.num_diagram_objects or 0) > 0
46
+
45
47
  def __init__(self, names: Optional[List[Name]] = None, **kwargs):
46
48
  super(IdentifiedObject, self).__init__(**kwargs)
47
49
  if names:
@@ -49,7 +51,10 @@ class IdentifiedObject(object, metaclass=ABCMeta):
49
51
  self.add_name(name.type, name.name)
50
52
 
51
53
  def __str__(self):
52
- return f"{self.__class__.__name__}{{{'|'.join(a for a in (str(self.mrid), str(self.name)) if a)}}}"
54
+ class_name = f'{self.__class__.__name__}'
55
+ if self.name:
56
+ return f'{class_name}{{{self.mrid}|{self.name}}}'
57
+ return f'{class_name}{{{self.mrid}}}'
53
58
 
54
59
  @property
55
60
  def names(self) -> Generator[Name, None, None]:
@@ -7,7 +7,7 @@ from __future__ import annotations
7
7
 
8
8
  __all__ = ["NameType"]
9
9
 
10
- from typing import Dict, List, Generator, overload, TYPE_CHECKING, Callable
10
+ from typing import Dict, List, Generator, overload, TYPE_CHECKING, Callable, Optional
11
11
 
12
12
  from zepben.ewb.dataclassy import dataclass
13
13
  from zepben.ewb.model.cim.iec61970.base.core.name import Name
@@ -30,7 +30,7 @@ class NameType:
30
30
  name: str
31
31
  """Name of the name type."""
32
32
 
33
- description: str = ""
33
+ description: Optional[str] = None
34
34
  """Description of the name type."""
35
35
 
36
36
  _names_index: Dict[str, Name] = dict()
@@ -32,7 +32,7 @@ class PowerSystemResource(IdentifiedObject):
32
32
  asset_info: Optional[AssetInfo] = None
33
33
  """A subclass of `zepben.ewb.model.cim.iec61968.assets.asset_info.AssetInfo` providing information about the asset associated with this PowerSystemResource."""
34
34
 
35
- num_controls: int = 0
35
+ num_controls: Optional[int] = None
36
36
  """Number of Control's known to associate with this [PowerSystemResource]"""
37
37
 
38
38
  _assets: Optional[List[Asset]] = None
@@ -48,7 +48,7 @@ class PowerSystemResource(IdentifiedObject):
48
48
  """
49
49
  * :return: True if this [PowerSystemResource] has at least 1 Control associated with it, false otherwise.
50
50
  """
51
- return self.num_controls > 0
51
+ return nlen(self.num_controls) > 0
52
52
 
53
53
  def num_assets(self) -> int:
54
54
  """
@@ -5,12 +5,14 @@
5
5
 
6
6
  __all__ = ["Analog"]
7
7
 
8
+ from typing import Optional
9
+
8
10
  from zepben.ewb.model.cim.iec61970.base.meas.measurement import Measurement
9
11
 
10
12
 
11
13
  class Analog(Measurement):
12
14
  """Analog represents an analog Measurement."""
13
15
 
14
- positive_flow_in: bool = False
16
+ positive_flow_in: Optional[bool] = None
15
17
  """If true then this measurement is an active power, reactive power or current with the convention that a positive value measured at the
16
18
  Terminal means power is flowing into the related PowerSystemResource."""
@@ -26,7 +26,7 @@ class EnergyConsumer(EnergyConnection):
26
26
  customer_count: Optional[int] = None
27
27
  """Number of individual customers represented by this demand."""
28
28
 
29
- grounded: bool = False
29
+ grounded: Optional[bool] = None
30
30
  """Used for Yn and Zn connections. True if the neutral is solidly grounded."""
31
31
 
32
32
  phase_connection: PhaseShuntConnectionKind = PhaseShuntConnectionKind.D
@@ -69,7 +69,7 @@ class EnergySource(EnergyConnection):
69
69
  xn: Optional[float] = None
70
70
  """Negative sequence Thevenin reactance."""
71
71
 
72
- is_external_grid: bool = False
72
+ is_external_grid: Optional[bool] = None
73
73
  """
74
74
  True if this energy source represents the higher-level power grid connection to an external grid
75
75
  that normally is modelled as the slack bus for power flow calculations.
@@ -21,7 +21,7 @@ class RegulatingCondEq(EnergyConnection):
21
21
  de-energized. Note that zero-impedance branches can potentially be modeled by other equipment types.
22
22
  """
23
23
 
24
- control_enabled: bool = True
24
+ control_enabled: Optional[bool] = None
25
25
  """Specifies the regulation status of the equipment. True is regulating, false is not regulating."""
26
26
 
27
27
  _regulating_control: Optional[RegulatingControl] = None
@@ -20,7 +20,7 @@ class ShuntCompensator(RegulatingCondEq):
20
20
  is an individual capacitor or reactor. A negative value for reactivePerSection indicates that the compensator is
21
21
  a reactor. ShuntCompensator is a single terminal device. Ground is implied.
22
22
  """
23
- grounded: bool = False
23
+ grounded: Optional[bool] = None
24
24
  """Used for Yn and Zn connections. True if the neutral is solidly grounded. nom_u : The voltage at which the nominal reactive power may be calculated.
25
25
  This should normally be within 10% of the voltage at which the capacitor is connected to the network."""
26
26
 
@@ -29,7 +29,7 @@ class SynchronousMachine(RotatingMachine):
29
29
  condenser_p: Optional[int] = None
30
30
  """Active power consumed (watts) when in condenser mode operation."""
31
31
 
32
- earthing: bool = False
32
+ earthing: Optional[bool] = None
33
33
  """Indicates whether the generator is earthed. Used for short circuit data exchange according to IEC 60909."""
34
34
 
35
35
  earthing_star_point_r: Optional[float] = None
@@ -19,7 +19,7 @@ class TapChanger(PowerSystemResource):
19
19
  Mechanism for changing transformer winding tap positions.
20
20
  """
21
21
 
22
- control_enabled: bool = True
22
+ control_enabled: Optional[bool] = None
23
23
  """Specifies the regulation status of the equipment. True is regulating, false is not regulating."""
24
24
 
25
25
  neutral_u: Optional[int] = None
@@ -24,7 +24,7 @@ class TransformerEnd(IdentifiedObject):
24
24
  In earlier CIM versions, the TransformerWinding class served a similar purpose, but this class is more flexible
25
25
  because it associates to terminal but is not a specialization of ConductingEquipment.
26
26
  """
27
- grounded: bool = False
27
+ grounded: Optional[bool] = None
28
28
  """(for Yn and Zn connections) True if the neutral is solidly grounded."""
29
29
 
30
30
  r_ground: Optional[float] = None