zepben.ewb 1.0.0b9__py3-none-any.whl → 1.0.1__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.
- zepben/ewb/auth/client/zepben_token_fetcher.py +62 -42
- zepben/ewb/database/sqlite/common/base_cim_reader.py +7 -7
- zepben/ewb/database/sqlite/common/base_database_writer.py +2 -2
- zepben/ewb/database/sqlite/network/network_cim_reader.py +20 -20
- zepben/ewb/database/sqlite/network/network_database_reader.py +4 -2
- zepben/ewb/database/sqlite/tables/iec61968/common/table_documents.py +5 -5
- zepben/ewb/database/sqlite/tables/iec61968/common/table_street_addresses.py +1 -1
- zepben/ewb/database/sqlite/tables/iec61968/infiec61968/infassets/table_poles.py +1 -1
- zepben/ewb/database/sqlite/tables/iec61970/base/core/table_identified_objects.py +3 -3
- zepben/ewb/database/sqlite/tables/iec61970/base/core/table_power_system_resources.py +1 -1
- zepben/ewb/database/sqlite/tables/iec61970/base/meas/table_analogs.py +1 -1
- zepben/ewb/database/sqlite/tables/iec61970/base/wires/table_energy_consumers.py +1 -1
- zepben/ewb/database/sqlite/tables/iec61970/base/wires/table_energy_sources.py +1 -1
- zepben/ewb/database/sqlite/tables/iec61970/base/wires/table_regulating_cond_eq.py +1 -1
- zepben/ewb/database/sqlite/tables/iec61970/base/wires/table_shunt_compensators.py +1 -1
- zepben/ewb/database/sqlite/tables/iec61970/base/wires/table_tap_changers.py +1 -1
- zepben/ewb/database/sqlite/tables/iec61970/base/wires/table_transformer_ends.py +1 -1
- zepben/ewb/model/cim/iec61968/common/document.py +5 -5
- zepben/ewb/model/cim/iec61968/common/street_address.py +2 -2
- zepben/ewb/model/cim/iec61968/common/street_detail.py +8 -7
- zepben/ewb/model/cim/iec61968/infiec61968/infassets/pole.py +1 -1
- zepben/ewb/model/cim/iec61968/metering/meter.py +4 -2
- zepben/ewb/model/cim/iec61968/metering/usage_point.py +1 -1
- zepben/ewb/model/cim/iec61970/base/core/curve.py +2 -1
- zepben/ewb/model/cim/iec61970/base/core/identified_object.py +8 -3
- zepben/ewb/model/cim/iec61970/base/core/name_type.py +2 -2
- zepben/ewb/model/cim/iec61970/base/core/power_system_resource.py +2 -2
- zepben/ewb/model/cim/iec61970/base/meas/analog.py +3 -1
- zepben/ewb/model/cim/iec61970/base/wires/energy_consumer.py +1 -1
- zepben/ewb/model/cim/iec61970/base/wires/energy_source.py +1 -1
- zepben/ewb/model/cim/iec61970/base/wires/regulating_cond_eq.py +1 -1
- zepben/ewb/model/cim/iec61970/base/wires/shunt_compensator.py +1 -1
- zepben/ewb/model/cim/iec61970/base/wires/synchronous_machine.py +1 -1
- zepben/ewb/model/cim/iec61970/base/wires/tap_changer.py +1 -1
- zepben/ewb/model/cim/iec61970/base/wires/transformer_end.py +1 -1
- zepben/ewb/model/cim/iec61970/base/wires/transformer_star_impedance.py +4 -4
- zepben/ewb/services/common/translator/base_cim2proto.py +21 -9
- zepben/ewb/services/common/translator/base_proto2cim.py +13 -8
- zepben/ewb/services/customer/translator/customer_cim2proto.py +10 -10
- zepben/ewb/services/customer/translator/customer_proto2cim.py +9 -9
- zepben/ewb/services/diagram/translator/diagram_cim2proto.py +8 -8
- zepben/ewb/services/diagram/translator/diagram_proto2cim.py +8 -8
- zepben/ewb/services/network/tracing/phases/phase_inferrer.py +2 -2
- zepben/ewb/services/network/translator/network_cim2proto.py +451 -322
- zepben/ewb/services/network/translator/network_proto2cim.py +305 -287
- {zepben_ewb-1.0.0b9.dist-info → zepben_ewb-1.0.1.dist-info}/METADATA +4 -6
- {zepben_ewb-1.0.0b9.dist-info → zepben_ewb-1.0.1.dist-info}/RECORD +50 -50
- {zepben_ewb-1.0.0b9.dist-info → zepben_ewb-1.0.1.dist-info}/WHEEL +0 -0
- {zepben_ewb-1.0.0b9.dist-info → zepben_ewb-1.0.1.dist-info}/licenses/LICENSE +0 -0
- {zepben_ewb-1.0.0b9.dist-info → zepben_ewb-1.0.1.dist-info}/top_level.txt +0 -0
|
@@ -7,12 +7,13 @@
|
|
|
7
7
|
__all__ = ["ZepbenTokenFetcher", "create_token_fetcher", "get_token_fetcher", "create_token_fetcher_managed_identity"]
|
|
8
8
|
|
|
9
9
|
import warnings
|
|
10
|
+
from dataclasses import dataclass, Field, field, InitVar
|
|
10
11
|
from datetime import datetime
|
|
11
|
-
from typing import Optional,
|
|
12
|
+
from typing import Optional, Callable
|
|
12
13
|
|
|
13
14
|
import jwt
|
|
14
15
|
import requests
|
|
15
|
-
from
|
|
16
|
+
from requests import Response
|
|
16
17
|
from urllib3.exceptions import InsecureRequestWarning
|
|
17
18
|
|
|
18
19
|
from zepben.ewb.auth.common.auth_exception import AuthException
|
|
@@ -21,11 +22,15 @@ from zepben.ewb.auth.common.auth_method import AuthMethod
|
|
|
21
22
|
from zepben.ewb.auth.common.auth_provider_config import AuthProviderConfig, create_auth_provider_config, fetch_provider_details
|
|
22
23
|
|
|
23
24
|
|
|
24
|
-
def _fetch_token_generator(
|
|
25
|
-
|
|
25
|
+
def _fetch_token_generator(
|
|
26
|
+
is_entraid: bool,
|
|
27
|
+
use_identity: bool,
|
|
28
|
+
identity_url: Optional[str] = None
|
|
29
|
+
) -> Callable[[dict, dict, str, Optional[bool], Optional[bool]], Response]:
|
|
30
|
+
|
|
26
31
|
def post(
|
|
27
|
-
refresh_request_data:
|
|
28
|
-
token_request_data:
|
|
32
|
+
refresh_request_data: dict,
|
|
33
|
+
token_request_data: dict,
|
|
29
34
|
token_endpoint: str,
|
|
30
35
|
refresh: bool,
|
|
31
36
|
verify: bool
|
|
@@ -48,7 +53,14 @@ def _fetch_token_generator(is_entraid: bool, use_identity: bool, identity_url: O
|
|
|
48
53
|
verify=verify
|
|
49
54
|
)
|
|
50
55
|
|
|
51
|
-
def _get_token_response(
|
|
56
|
+
def _get_token_response(
|
|
57
|
+
refresh_request_data: dict,
|
|
58
|
+
token_request_data: dict,
|
|
59
|
+
token_endpoint: str,
|
|
60
|
+
refresh: bool,
|
|
61
|
+
verify: bool
|
|
62
|
+
) -> requests.Response:
|
|
63
|
+
|
|
52
64
|
refresh = not is_entraid and refresh # At the moment Azure auth doesn't support refresh tokens. So we always force new tokens.
|
|
53
65
|
|
|
54
66
|
return post(
|
|
@@ -59,53 +71,59 @@ def _fetch_token_generator(is_entraid: bool, use_identity: bool, identity_url: O
|
|
|
59
71
|
verify
|
|
60
72
|
)
|
|
61
73
|
|
|
62
|
-
def _get_token_response_from_identity(
|
|
63
|
-
|
|
74
|
+
def _get_token_response_from_identity(
|
|
75
|
+
refresh_request_data: dict,
|
|
76
|
+
token_request_data: dict,
|
|
77
|
+
token_endpoint: str,
|
|
78
|
+
refresh: Optional[bool] = False,
|
|
79
|
+
verify: Optional[bool] = False
|
|
80
|
+
) -> requests.Response:
|
|
81
|
+
|
|
64
82
|
return requests.get(identity_url, headers={"Metadata": "true"}, verify=verify)
|
|
65
83
|
|
|
66
84
|
if use_identity:
|
|
67
85
|
if not identity_url:
|
|
68
|
-
raise ValueError("Misconfiguration
|
|
86
|
+
raise ValueError("Misconfiguration detected - if use_identity is true, identity_url must also be provided. This is a bug, contact Zepben.")
|
|
69
87
|
return _get_token_response_from_identity
|
|
70
88
|
else:
|
|
71
89
|
return _get_token_response
|
|
72
90
|
|
|
73
91
|
|
|
74
|
-
@dataclass
|
|
75
|
-
class ZepbenTokenFetcher
|
|
92
|
+
@dataclass(init=True, repr=True, eq=True)
|
|
93
|
+
class ZepbenTokenFetcher:
|
|
76
94
|
"""
|
|
77
95
|
Fetches access tokens from an authentication provider using the OAuth 2.0 protocol.
|
|
78
|
-
"""
|
|
79
96
|
|
|
80
|
-
|
|
81
|
-
|
|
97
|
+
:param audience: Audience to use when requesting tokens
|
|
98
|
+
:param token_endpoint: The domain of the token issuer.
|
|
99
|
+
:param token_request_data: Data to pass in token requests.
|
|
100
|
+
:param refresh_request_data: Data to pass in refresh token requests.
|
|
101
|
+
:param verify: Passed through to requests.post(). When this is a boolean, it determines whether to verify the HTTPS
|
|
102
|
+
certificate of the OAUTH service or not. When this is a string, it is used as the filename of the certificate
|
|
103
|
+
truststore to use when verifying the OAUTH service.
|
|
104
|
+
:param auth_method: Deprecated. Kept for backwards compatibility, but this is now unused.
|
|
105
|
+
"""
|
|
82
106
|
|
|
83
107
|
audience: str
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
""" Data to pass in token requests. """
|
|
91
|
-
|
|
92
|
-
refresh_request_data = {}
|
|
93
|
-
""" Data to pass in refresh token requests. """
|
|
108
|
+
issuer: Optional[str] = None
|
|
109
|
+
token_endpoint: Optional[str] = None
|
|
110
|
+
token_request_data: Optional[dict] = field(default_factory=dict)
|
|
111
|
+
refresh_request_data: Optional[dict] = field(default_factory=dict)
|
|
112
|
+
verify: Optional[bool | str] = None
|
|
113
|
+
auth_method: Optional[AuthMethod] = None
|
|
94
114
|
|
|
95
|
-
|
|
96
|
-
"""
|
|
97
|
-
Passed through to requests.post(). When this is a boolean, it determines whether or not to verify the HTTPS certificate of the OAUTH service.
|
|
98
|
-
When this is a string, it is used as the filename of the certificate truststore to use when verifying the OAUTH service.
|
|
99
|
-
"""
|
|
115
|
+
_request_token: InitVar[Callable[[dict, dict, str, Optional[bool], Optional[bool]], requests.Response]] = None
|
|
100
116
|
|
|
101
|
-
|
|
117
|
+
_access_token: Optional[str] = None
|
|
118
|
+
_refresh_token: Optional[str] = None
|
|
119
|
+
_token_expiry: Optional[datetime] = datetime.min
|
|
120
|
+
token_type: Optional[str] = None
|
|
102
121
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
122
|
+
def __post_init__(self, _request_token):
|
|
123
|
+
if _request_token is None:
|
|
124
|
+
_request_token = _fetch_token_generator(False, False)
|
|
125
|
+
self._request_token = _request_token
|
|
107
126
|
|
|
108
|
-
def __init__(self):
|
|
109
127
|
self.token_request_data["audience"] = self.audience
|
|
110
128
|
self.refresh_request_data["audience"] = self.audience
|
|
111
129
|
|
|
@@ -134,7 +152,7 @@ class ZepbenTokenFetcher(object):
|
|
|
134
152
|
|
|
135
153
|
return f"{self._token_type} {self._access_token}"
|
|
136
154
|
|
|
137
|
-
def _fetch_token(self, refresh: bool = False):
|
|
155
|
+
def _fetch_token(self, refresh: Optional[bool] = False):
|
|
138
156
|
if refresh:
|
|
139
157
|
self.refresh_request_data["refresh_token"] = self._refresh_token
|
|
140
158
|
|
|
@@ -174,11 +192,11 @@ class ZepbenTokenFetcher(object):
|
|
|
174
192
|
|
|
175
193
|
def create_token_fetcher(
|
|
176
194
|
conf_address: str,
|
|
177
|
-
verify_conf:
|
|
178
|
-
verify_auth:
|
|
179
|
-
auth_type_field: str = "authType",
|
|
180
|
-
audience_field: str = "audience",
|
|
181
|
-
issuer_field: str = "issuer",
|
|
195
|
+
verify_conf: Optional[bool | str] = True,
|
|
196
|
+
verify_auth: Optional[bool | str] = True,
|
|
197
|
+
auth_type_field: Optional[str] = "authType",
|
|
198
|
+
audience_field: Optional[str] = "audience",
|
|
199
|
+
issuer_field: Optional[str] = "issuer",
|
|
182
200
|
) -> Optional[ZepbenTokenFetcher]:
|
|
183
201
|
"""
|
|
184
202
|
Helper method to fetch auth related configuration from `conf_address` and create a :class:`ZepbenTokenFetcher`
|
|
@@ -194,6 +212,7 @@ def create_token_fetcher(
|
|
|
194
212
|
|
|
195
213
|
:returns: A :class:`ZepbenTokenFetcher` if the server reported authentication was configured, otherwise None.
|
|
196
214
|
"""
|
|
215
|
+
|
|
197
216
|
with warnings.catch_warnings():
|
|
198
217
|
if not verify_conf:
|
|
199
218
|
warnings.filterwarnings("ignore", category=InsecureRequestWarning)
|
|
@@ -264,6 +283,7 @@ def create_token_fetcher_managed_identity(identity_url: str, verify_auth: bool)
|
|
|
264
283
|
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=5ffcfee6-34cd-4c5c-bb7e-c5261d739341"
|
|
265
284
|
:param verify_auth: Whether to verify certificates for the identity_url. Only applies for https URLs.
|
|
266
285
|
"""
|
|
286
|
+
|
|
267
287
|
return ZepbenTokenFetcher(
|
|
268
288
|
audience="",
|
|
269
289
|
issuer="",
|
|
@@ -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
|
|
158
|
-
|
|
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.
|
|
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.
|
|
21
|
-
self.type: Column = self._create_column("type", "TEXT", Nullable.
|
|
22
|
-
self.status: Column = self._create_column("status", "TEXT", Nullable.
|
|
23
|
-
self.comment: Column = self._create_column("comment", "TEXT", Nullable.
|
|
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.
|
|
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.
|
|
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.
|
|
20
|
-
self.description: Column = self._create_column("description", "TEXT", Nullable.
|
|
21
|
-
self.num_diagram_objects: Column = self._create_column("num_diagram_objects", "INTEGER", Nullable.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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):
|
|
@@ -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 =
|
|
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
|