Skip to content

Commit 18c3509

Browse files
chestm007kgreav
andauthored
[DEV-3798] SDK 1.0.0 support (#199)
Signed-off-by: Max Chesterfield <max.chesterfield@zepben.com> Signed-off-by: Kurt Greaves <kurt.greaves@zepben.com> Co-authored-by: Kurt Greaves <kurt.greaves@zepben.com>
1 parent e892088 commit 18c3509

70 files changed

Lines changed: 1292 additions & 1078 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

changelog.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,27 @@
8888
* The `zepben.auth` dependency has been incorporated into the SDK with the following package change:
8989
* `zepben.auth` -> `zepben.ewb.auth`. You can also import these directly from `zepben.ewb`.
9090
* `SqliteTable` now subclasses `SqlTable`.
91+
* The following CIM fields have been made nullable. Note if previously accessing these fields you will now have to handle them potentially being null.
92+
* `Analog.positiveFlowIn`
93+
* `Document.*`
94+
* `EnergyConsumer.grounded`
95+
* `EnergySource.isExternalGrid`
96+
* `IdentifiedObject.name`
97+
* `IdentifiedObject.description`
98+
* `IdentifiedObject.numDiagramObjects`
99+
* `Meter.companyMeterId`
100+
* `NameType.description`
101+
* `Pole.classification`
102+
* `PowerSystemResource.numControls`
103+
* `RegulatingCondEq.controlEnabled`
104+
* `ShuntCompensator.grounded`
105+
* `StreetAddress.postalCode`
106+
* `StreetAddress.poBox`
107+
* `StreetDetail.*`
108+
* `SynchronousMachine.earthing`
109+
* `TapChanger.controlEnabled`
110+
* `TransformerEnd.grounded`
111+
* `UsagePoint.isVirtual`
91112

92113
### New Features
93114
* Created a new `SqlTable` that doesn't support creating schema creation statements by default.

pyproject.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@
1717
description = "Python SDK for interacting with the Energy Workbench platform"
1818
readme = {file = "README.md", content-type = "text/markdown"}
1919
license = "MPL-2.0"
20-
requires-python = '>=3.9,<3.13'
20+
requires-python = '>=3.10,<3.13'
2121
authors = [
2222
{name = "Kurt Greaves", email = "kurt.greaves@zepben.com"},
2323
{name = "Max Chesterfield", email = "max.chesterfield@zepben.com"}
2424
]
2525
dependencies = [
26-
"zepben.protobuf==1.0.0b1",
26+
"zepben.protobuf==1.0.0",
2727
"typing_extensions==4.12.2",
2828
"requests>=2.26.0, <3.0.0",
2929
"urllib3>=1.26.6, <1.27.0",
@@ -32,7 +32,6 @@
3232
]
3333
classifiers = [
3434
"Programming Language :: Python :: 3",
35-
"Programming Language :: Python :: 3.9",
3635
"Programming Language :: Python :: 3.10",
3736
"Programming Language :: Python :: 3.11",
3837
"Programming Language :: Python :: 3.12",

src/zepben/ewb/database/sqlite/common/base_cim_reader.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,12 @@ def _load_document(self, document: Document, table: TableDocuments, result_set:
5353
:return: True if the `Document` was successfully read from the database and added to the service.
5454
:raises SQLException: For any errors encountered reading from the database.
5555
"""
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)
5757
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)
6262

6363
return self._load_identified_object(document, table, result_set)
6464

@@ -111,8 +111,8 @@ def _load_identified_object(identified_object: IdentifiedObject, table: TableIde
111111
:return: True if the `IdentifiedObject` was successfully read from the database and added to the service.
112112
:raises SQLException: For any errors encountered reading from the database.
113113
"""
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)
116116
# Currently unused
117117
# identified_object.num_diagram_objects = result_set.get_int(table.num_diagram_objects.query_index)
118118

src/zepben/ewb/database/sqlite/common/base_database_writer.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from contextlib import closing
1212
from pathlib import Path
1313
from sqlite3 import Connection, Cursor, OperationalError
14-
from typing import Callable, Union
14+
from typing import Callable, Union, Optional
1515

1616
from zepben.ewb.database.sqlite.common.base_database_tables import BaseDatabaseTables
1717
from zepben.ewb.database.sqlite.common.base_service_writer import BaseServiceWriter
@@ -66,7 +66,7 @@ def __init__(
6666
Provider of the connection to the specified database.
6767
"""
6868

69-
self._save_connection: Connection
69+
self._save_connection: Optional[Connection] = None
7070
self._has_been_used: bool = False
7171

7272
def save(self) -> bool:

src/zepben/ewb/database/sqlite/network/network_cim_reader.py

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,22 +1070,22 @@ def load_position_point(self, table: TablePositionPoints, result_set: ResultSet,
10701070

10711071
def _load_street_address(self, table: TableStreetAddresses, result_set: ResultSet) -> StreetAddress:
10721072
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),
10741074
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),
10761076
self._load_street_detail(table, result_set)
10771077
)
10781078

10791079
@staticmethod
10801080
def _load_street_detail(table: TableStreetAddresses, result_set: ResultSet) -> Optional[StreetDetail]:
10811081
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)
10891089
)
10901090

10911091
return sd if not sd.all_fields_empty() else None
@@ -1178,7 +1178,7 @@ def load_pole(self, table: TablePoles, result_set: ResultSet, set_identifier: Ca
11781178
"""
11791179
pole = Pole(mrid=set_identifier(result_set.get_string(table.mrid.query_index)))
11801180

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)
11821182

11831183
return self._load_structure(pole, table, result_set) and self._add_or_throw(pole)
11841184

@@ -1232,7 +1232,7 @@ def load_usage_point(self, table: TableUsagePoints, result_set: ResultSet, set_i
12321232
result_set.get_string(table.location_mrid.query_index, on_none=None),
12331233
Location
12341234
)
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)
12361236
usage_point.connection_category = result_set.get_string(table.connection_category.query_index, on_none=None)
12371237
usage_point.rated_power = result_set.get_int(table.rated_power.query_index, on_none=None)
12381238
usage_point.approved_inverter_capacity = result_set.get_int(table.approved_inverter_capacity.query_index, on_none=None)
@@ -1472,7 +1472,7 @@ def _load_power_system_resource(self, power_system_resource: PowerSystemResource
14721472
result_set.get_string(table.location_mrid.query_index, on_none=None),
14731473
Location
14741474
)
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)
14761476

14771477
return self._load_identified_object(power_system_resource, table, result_set)
14781478

@@ -1686,7 +1686,7 @@ def load_analog(self, table: TableAnalogs, result_set: ResultSet, set_identifier
16861686
"""
16871687
meas = Analog(mrid=set_identifier(result_set.get_string(table.mrid.query_index)))
16881688

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)
16901690

16911691
return self._load_measurement(meas, table, result_set) and self._add_or_throw(meas)
16921692

@@ -1956,7 +1956,7 @@ def load_energy_consumer(self, table: TableEnergyConsumers, result_set: ResultSe
19561956
energy_consumer = EnergyConsumer(mrid=set_identifier(result_set.get_string(table.mrid.query_index)))
19571957

19581958
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)
19601960
energy_consumer.p = result_set.get_float(table.p.query_index, on_none=None)
19611961
energy_consumer.q = result_set.get_float(table.q.query_index, on_none=None)
19621962
energy_consumer.p_fixed = result_set.get_float(table.p_fixed.query_index, on_none=None)
@@ -2018,7 +2018,7 @@ def load_energy_source(self, table: TableEnergySources, result_set: ResultSet, s
20182018
energy_source.x = result_set.get_float(table.x.query_index, on_none=None)
20192019
energy_source.x0 = result_set.get_float(table.x0.query_index, on_none=None)
20202020
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)
20222022
energy_source.r_min = result_set.get_float(table.r_min.query_index, on_none=None)
20232023
energy_source.rn_min = result_set.get_float(table.rn_min.query_index, on_none=None)
20242024
energy_source.r0_min = result_set.get_float(table.r0_min.query_index, on_none=None)
@@ -2488,7 +2488,7 @@ def load_recloser(self, table: TableReclosers, result_set: ResultSet, set_identi
24882488
return self._load_protected_switch(recloser, table, result_set) and self._add_or_throw(recloser)
24892489

24902490
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)
24922492
# We use a resolver here because there is an ordering conflict between terminals, RegulatingCondEq, and RegulatingControls
24932493
# We check this resolver has actually been resolved in the postLoad of the database read and throw there if it hasn't.
24942494
self._service.resolve_or_defer_reference(
@@ -2556,7 +2556,7 @@ def _load_shunt_compensator(self, shunt_compensator: ShuntCompensator, table: Ta
25562556
ShuntCompensatorInfo
25572557
)
25582558

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)
25602560
shunt_compensator.nom_u = result_set.get_int(table.nom_u.query_index, on_none=None)
25612561
shunt_compensator.phase_connection = PhaseShuntConnectionKind[result_set.get_string(table.phase_connection.query_index)]
25622562
shunt_compensator.sections = result_set.get_float(table.sections.query_index, on_none=None)
@@ -2610,7 +2610,7 @@ def load_synchronous_machine(self, table: TableSynchronousMachines, result_set:
26102610

26112611
synchronous_machine.base_q = result_set.get_float(table.base_q.query_index, on_none=None)
26122612
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)
26142614
synchronous_machine.earthing_star_point_r = result_set.get_float(table.earthing_star_point_r.query_index, on_none=None)
26152615
synchronous_machine.earthing_star_point_x = result_set.get_float(table.earthing_star_point_x.query_index, on_none=None)
26162616
synchronous_machine.ikk = result_set.get_float(table.ikk.query_index, on_none=None)
@@ -2633,7 +2633,7 @@ def load_synchronous_machine(self, table: TableSynchronousMachines, result_set:
26332633
return self._load_rotating_machine(synchronous_machine, table, result_set) and self._add_or_throw(synchronous_machine)
26342634

26352635
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)
26372637
tap_changer.high_step = result_set.get_int(table.high_step.query_index, on_none=None)
26382638
tap_changer.low_step = result_set.get_int(table.low_step.query_index, on_none=None)
26392639
tap_changer.neutral_step = result_set.get_int(table.neutral_step.query_index, on_none=None)
@@ -2681,7 +2681,7 @@ def _load_transformer_end(self, transformer_end: TransformerEnd, table: TableTra
26812681
result_set.get_string(table.base_voltage_mrid.query_index, on_none=None),
26822682
BaseVoltage
26832683
)
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)
26852685
transformer_end.r_ground = result_set.get_float(table.r_ground.query_index, on_none=None)
26862686
transformer_end.x_ground = result_set.get_float(table.x_ground.query_index, on_none=None)
26872687
transformer_end.star_impedance = self._ensure_get(

src/zepben/ewb/database/sqlite/network/network_database_reader.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,11 @@ def head_conducting_equipment_mrid(feeder: Feeder) -> Optional[str]:
154154
feeder_start_points = set(map(head_conducting_equipment_mrid, self.service.objects(Feeder)))
155155

156156
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)
159160
and feeder_start_points.isdisjoint({it.to_equip.mrid for it in connected_equipment(energy_source) if it.to_equip})
161+
)
160162

161163
for es in self.service.objects(EnergySource):
162164
if has_been_assigned_to_feeder(es):

src/zepben/ewb/database/sqlite/tables/iec61968/common/table_documents.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ class TableDocuments(TableIdentifiedObjects, ABC):
1515

1616
def __init__(self):
1717
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)
1919
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)

src/zepben/ewb/database/sqlite/tables/iec61968/common/table_street_addresses.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class TableStreetAddresses(TableTownDetails, ABC):
1515

1616
def __init__(self):
1717
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)
1919
self.po_box: Column = self._create_column("po_box", "TEXT", Nullable.NULL)
2020
self.building_name: Column = self._create_column("building_name", "TEXT", Nullable.NULL)
2121
self.floor_identification: Column = self._create_column("floor_identification", "TEXT", Nullable.NULL)

src/zepben/ewb/database/sqlite/tables/iec61968/infiec61968/infassets/table_poles.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class TablePoles(TableStructures):
1313

1414
def __init__(self):
1515
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)
1717

1818
@property
1919
def name(self) -> str:

src/zepben/ewb/database/sqlite/tables/iec61970/base/core/table_identified_objects.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ class TableIdentifiedObjects(SqliteTable, ABC):
1616

1717
def __init__(self):
1818
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)
2222

2323
@property
2424
def unique_index_columns(self) -> Generator[List[Column], None, None]:

0 commit comments

Comments
 (0)