s2-python 0.6.0__py3-none-any.whl → 0.7.0__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.
- {s2_python-0.6.0.dist-info → s2_python-0.7.0.dist-info}/METADATA +1 -3
- {s2_python-0.6.0.dist-info → s2_python-0.7.0.dist-info}/RECORD +13 -13
- s2python/common/power_forecast_element.py +2 -2
- s2python/common/power_measurement.py +2 -2
- s2python/ombc/ombc_operation_mode.py +1 -1
- s2python/ombc/ombc_system_description.py +1 -1
- s2python/s2_parser.py +1 -2
- s2python/s2_validation_error.py +1 -7
- s2python/validate_values_mixin.py +23 -12
- {s2_python-0.6.0.dist-info → s2_python-0.7.0.dist-info}/WHEEL +0 -0
- {s2_python-0.6.0.dist-info → s2_python-0.7.0.dist-info}/entry_points.txt +0 -0
- {s2_python-0.6.0.dist-info → s2_python-0.7.0.dist-info}/licenses/LICENSE +0 -0
- {s2_python-0.6.0.dist-info → s2_python-0.7.0.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: s2-python
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.7.0
|
4
4
|
Summary: S2 Protocol Python Wrapper
|
5
5
|
Author-email: Flexiblepower <info@info.nl>
|
6
6
|
License-Expression: Apache-2.0
|
@@ -54,8 +54,6 @@ Python Wrapper for S2 Flexibility Protocol
|
|
54
54
|
This Python package implements the message validation for the EN50491-12-2 "S2" standard for home and building energy management. This implementation
|
55
55
|
is based on the asyncapi description of the protocol provided in the `s2-ws-json <https://github.com/flexiblepower/s2-ws-json/>`_ repository.
|
56
56
|
|
57
|
-
Currently, the package supports the *common* and *FILL RATE BASED CONTROL* types and messages.
|
58
|
-
|
59
57
|
To Install
|
60
58
|
-----------
|
61
59
|
You can install this package using pip or any Python dependency manager that collects the packages from PyPI:
|
@@ -1,14 +1,14 @@
|
|
1
|
-
s2_python-0.
|
1
|
+
s2_python-0.7.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
2
2
|
s2python/__init__.py,sha256=e5lwvqsPl-z7IfEd0hRQhLBRKBYcuw2eqrecXnMfLdg,384
|
3
3
|
s2python/message.py,sha256=62DtKyfovcDM4Eroc33i72ZnQScWDV7sUvYifagXcmI,3352
|
4
4
|
s2python/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
5
|
s2python/reception_status_awaiter.py,sha256=jKMliFk1XxwsEGtx3vFESbJhUtClB7cTu-td90-qBN8,2137
|
6
6
|
s2python/s2_connection.py,sha256=QGpYtIxoRXIKeiw-1C7MywxxLwT1OwwqMxUVZ-NJ79Y,21685
|
7
7
|
s2python/s2_control_type.py,sha256=uLZb_7l2mmqY6tJk3KuQYGpKRnZaDyLZ-E8YvAGFCwQ,4192
|
8
|
-
s2python/s2_parser.py,sha256=
|
9
|
-
s2python/s2_validation_error.py,sha256=
|
8
|
+
s2python/s2_parser.py,sha256=LoeqLmKkm3ZLU4gv4IwaxLUSt0mq5rFN94KFSOFgGXI,4556
|
9
|
+
s2python/s2_validation_error.py,sha256=FVf5Vm7ilS2BwkJac4G2xxDO8f3tOK92mD1ygHq_d0k,173
|
10
10
|
s2python/utils.py,sha256=QX9b-mi-H_YUGTmGmJsrAbaWWM3dgaoaRLRXHHlaZDE,212
|
11
|
-
s2python/validate_values_mixin.py,sha256=
|
11
|
+
s2python/validate_values_mixin.py,sha256=OQAnD0ZgGh8nmGE-jF1GjWkh1eEwwL25-P29tsj8io8,2713
|
12
12
|
s2python/version.py,sha256=IBzoytgbYYYekQnSTfSmWeYAZ4c_yUFU2oLIAG4UYjs,45
|
13
13
|
s2python/common/__init__.py,sha256=zJizo6qfnWGQ75iWZZZsojPv_ATjVqT-Sj4hBKgE8X0,1991
|
14
14
|
s2python/common/duration.py,sha256=7u2SF7rWtwLfehD9RUiY1Mhntnah1ctvYjin04ZiYnI,714
|
@@ -17,9 +17,9 @@ s2python/common/handshake_response.py,sha256=aJyZSl62wUUdtrJ4WFzu4ZIlhl-4wjxdyQ7
|
|
17
17
|
s2python/common/instruction_status_update.py,sha256=z1nt5ToXinuX44N-t-w5oCYXQtG27q9QZEsg1xsISwY,735
|
18
18
|
s2python/common/number_range.py,sha256=twkIKKtSHtxb4eegwPaDSIGRDWzHAH3gm5t3SPbIyfo,739
|
19
19
|
s2python/common/power_forecast.py,sha256=XXtRJWeHDa-mkr4FnHrN55Fp_byBmTLsaAQKqO7Zcpo,757
|
20
|
-
s2python/common/power_forecast_element.py,sha256=
|
20
|
+
s2python/common/power_forecast_element.py,sha256=nJedTRyMusdAZRD2HFps0Q1c3LvccBxHVnSQZm-Va6Y,1612
|
21
21
|
s2python/common/power_forecast_value.py,sha256=-tIGJn1ME4ozVmg1jdoEWUYT4Eb5uxvp443TmJpmBB0,389
|
22
|
-
s2python/common/power_measurement.py,sha256=
|
22
|
+
s2python/common/power_measurement.py,sha256=m6OnsZsb_DQ8RCFtcO7BvjVOTJ7T-i7ReE-fJMlKAFw,1492
|
23
23
|
s2python/common/power_range.py,sha256=zb8Juw9WtV-UvkICRIO6LGvCt19eqErryKoQe2S3Kog,702
|
24
24
|
s2python/common/power_value.py,sha256=mjHEPWFzMAZPJ0P5M9zASHf5uIW47kM8SqqdVaZCkAs,349
|
25
25
|
s2python/common/reception_status.py,sha256=Lf6c81jq5VWUTFgGmmTUly3PK82MmRrt4n6T3zdG-aA,541
|
@@ -61,9 +61,9 @@ s2python/generated/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
|
|
61
61
|
s2python/generated/gen_s2.py,sha256=l1jzvXGSRa09nu6GBN8Mg4z_2HfwtY3aQeBHbmrBJFM,63431
|
62
62
|
s2python/ombc/__init__.py,sha256=gwSNmlgU35lm4W1y-pvaP5h7urpdWhy0rUuUL16qaO4,309
|
63
63
|
s2python/ombc/ombc_instruction.py,sha256=_my3X76uUPwDXMjqfkSLPzHQhw1eeFV54nBrFkzDqCE,944
|
64
|
-
s2python/ombc/ombc_operation_mode.py,sha256
|
64
|
+
s2python/ombc/ombc_operation_mode.py,sha256=g8KLLHrLm5Yt6kogPZXv8K4yoKPdMcKrcQPMTI3sy4I,908
|
65
65
|
s2python/ombc/ombc_status.py,sha256=4SDZUYAGGYiTEo68swDo_9IrmJPfMby3aPQ9XnLzmUo,593
|
66
|
-
s2python/ombc/ombc_system_description.py,sha256=
|
66
|
+
s2python/ombc/ombc_system_description.py,sha256=tdbL_dWgwhB-zE3IK7NTas_qSjjrGc1ci_L3istNvUE,1147
|
67
67
|
s2python/ombc/ombc_timer_status.py,sha256=qaLyY9Jl16hqoIEDR5tTuoSttMHHsRdh-AxvTgODxx0,606
|
68
68
|
s2python/pebc/__init__.py,sha256=O8CONhsj4ZEN9bPbPPZwxvr3DxMN8HnGAwdlXVT2kA8,781
|
69
69
|
s2python/pebc/pebc_allowed_limit_range.py,sha256=_-6cuAd2wtbe7p3WPr_8WS9BD-_mb8Nmr2oKpNdS0jo,1996
|
@@ -82,8 +82,8 @@ s2python/ppbc/ppbc_power_sequence_container_status.py,sha256=KhbyqgzX2yncYT6TkHG
|
|
82
82
|
s2python/ppbc/ppbc_power_sequence_element.py,sha256=AbCk4lqpBkP8ppE4gMfOGLpcC53pBIcm81fUDZp5xAM,850
|
83
83
|
s2python/ppbc/ppbc_schedule_instruction.py,sha256=C-MUpHhUMPKebmHlT8ClpmKvtLzPgs4MAq10mVcmi6Y,1291
|
84
84
|
s2python/ppbc/ppbc_start_interruption_instruction.py,sha256=cZndUsFhBtKAmTM89qYTF74Y_SUIy1jukn7-Zz-YLo8,1420
|
85
|
-
s2_python-0.
|
86
|
-
s2_python-0.
|
87
|
-
s2_python-0.
|
88
|
-
s2_python-0.
|
89
|
-
s2_python-0.
|
85
|
+
s2_python-0.7.0.dist-info/METADATA,sha256=X2knF3WhTMa-xiBGZ0I76rq3dL_CuaXOzMlKYLRHbwM,3718
|
86
|
+
s2_python-0.7.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
87
|
+
s2_python-0.7.0.dist-info/entry_points.txt,sha256=feX-xmgJZgSe5-jxMgFKPKCJz4Ys3eQcGrsXsirNZyM,61
|
88
|
+
s2_python-0.7.0.dist-info/top_level.txt,sha256=OLFq0oDhr77Mp-EYLEcWk5P3jvooOt4IHkTI5KYJMc8,9
|
89
|
+
s2_python-0.7.0.dist-info/RECORD,,
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import List
|
1
|
+
from typing import List, Dict
|
2
2
|
from typing_extensions import Self
|
3
3
|
|
4
4
|
from pydantic import model_validator
|
@@ -29,7 +29,7 @@ class PowerForecastElement(GenPowerForecastElement, S2MessageComponent):
|
|
29
29
|
def validate_values_at_most_one_per_commodity_quantity(self) -> Self:
|
30
30
|
"""Validates the power measurement values to check that there is at most 1 PowerValue per CommodityQuantity."""
|
31
31
|
|
32
|
-
has_value:
|
32
|
+
has_value: Dict[CommodityQuantity, bool] = {}
|
33
33
|
|
34
34
|
for value in self.power_values:
|
35
35
|
if has_value.get(value.commodity_quantity, False):
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import uuid
|
2
|
-
from typing import List
|
2
|
+
from typing import List, Dict
|
3
3
|
from typing_extensions import Self
|
4
4
|
|
5
5
|
from pydantic import model_validator
|
@@ -26,7 +26,7 @@ class PowerMeasurement(GenPowerMeasurement, S2MessageComponent):
|
|
26
26
|
def validate_values_at_most_one_per_commodity_quantity(self) -> Self:
|
27
27
|
"""Validates the power measurement values to check that there is at most 1 PowerValue per CommodityQuantity."""
|
28
28
|
|
29
|
-
has_value:
|
29
|
+
has_value: Dict[CommodityQuantity, bool] = {}
|
30
30
|
|
31
31
|
for value in self.values:
|
32
32
|
if has_value.get(value.commodity_quantity, False):
|
@@ -17,7 +17,7 @@ class OMBCOperationMode(GenOMBCOperationMode, S2MessageComponent):
|
|
17
17
|
model_config["validate_assignment"] = True
|
18
18
|
|
19
19
|
id: uuid.UUID = GenOMBCOperationMode.model_fields["id"] # type: ignore[assignment]
|
20
|
-
power_ranges: List[PowerRange] = GenOMBCOperationMode.model_fields[
|
20
|
+
power_ranges: List[PowerRange] = GenOMBCOperationMode.model_fields[ # type: ignore[reportIncompatibleVariableOverride]
|
21
21
|
"power_ranges"
|
22
22
|
] # type: ignore[assignment]
|
23
23
|
abnormal_condition_only: bool = GenOMBCOperationMode.model_fields[
|
@@ -18,7 +18,7 @@ class OMBCSystemDescription(GenOMBCSystemDescription, S2MessageComponent):
|
|
18
18
|
model_config["validate_assignment"] = True
|
19
19
|
|
20
20
|
message_id: uuid.UUID = GenOMBCSystemDescription.model_fields["message_id"] # type: ignore[assignment]
|
21
|
-
operation_modes: List[OMBCOperationMode] = GenOMBCSystemDescription.model_fields[
|
21
|
+
operation_modes: List[OMBCOperationMode] = GenOMBCSystemDescription.model_fields[ # type: ignore[reportIncompatibleVariableOverride]
|
22
22
|
"operation_modes"
|
23
23
|
] # type: ignore[assignment]
|
24
24
|
transitions: List[Transition] = GenOMBCSystemDescription.model_fields["transitions"] # type: ignore[assignment]
|
s2python/s2_parser.py
CHANGED
@@ -88,10 +88,9 @@ class S2Parser:
|
|
88
88
|
None,
|
89
89
|
message_json,
|
90
90
|
f"Unable to parse {message_type} as an S2 message. Type unknown.",
|
91
|
-
None,
|
92
91
|
)
|
93
92
|
|
94
|
-
return TYPE_TO_MESSAGE_CLASS[message_type].
|
93
|
+
return TYPE_TO_MESSAGE_CLASS[message_type].from_dict(message_json)
|
95
94
|
|
96
95
|
@staticmethod
|
97
96
|
def parse_as_message(
|
s2python/s2_validation_error.py
CHANGED
@@ -1,8 +1,5 @@
|
|
1
1
|
from dataclasses import dataclass
|
2
|
-
from typing import
|
3
|
-
|
4
|
-
from pydantic import ValidationError
|
5
|
-
from pydantic.v1.error_wrappers import ValidationError as ValidationErrorV1
|
2
|
+
from typing import Type, Optional
|
6
3
|
|
7
4
|
|
8
5
|
@dataclass
|
@@ -10,6 +7,3 @@ class S2ValidationError(Exception):
|
|
10
7
|
class_: Optional[Type]
|
11
8
|
obj: object
|
12
9
|
msg: str
|
13
|
-
pydantic_validation_error: Union[
|
14
|
-
ValidationErrorV1, ValidationError, TypeError, None
|
15
|
-
]
|
@@ -12,8 +12,6 @@ from typing import (
|
|
12
12
|
|
13
13
|
from typing_extensions import Self
|
14
14
|
|
15
|
-
from pydantic.v1.error_wrappers import display_errors # pylint: disable=no-name-in-module
|
16
|
-
|
17
15
|
from pydantic import ( # pylint: disable=no-name-in-module
|
18
16
|
BaseModel,
|
19
17
|
ValidationError,
|
@@ -28,12 +26,20 @@ MappingIntStrAny = Mapping[IntStr, Any]
|
|
28
26
|
|
29
27
|
|
30
28
|
class S2MessageComponent(BaseModel):
|
29
|
+
def __setattr__(self, name: str, value: Any) -> None:
|
30
|
+
try:
|
31
|
+
super().__setattr__(name, value)
|
32
|
+
except (ValidationError, TypeError) as e:
|
33
|
+
raise S2ValidationError(
|
34
|
+
type(self), self, "Pydantic raised a validation error.",
|
35
|
+
) from e
|
36
|
+
|
31
37
|
def to_json(self) -> str:
|
32
38
|
try:
|
33
39
|
return self.model_dump_json(by_alias=True, exclude_none=True)
|
34
40
|
except (ValidationError, TypeError) as e:
|
35
41
|
raise S2ValidationError(
|
36
|
-
type(self), self, "Pydantic raised a
|
42
|
+
type(self), self, "Pydantic raised a validation error.",
|
37
43
|
) from e
|
38
44
|
|
39
45
|
def to_dict(self) -> Dict[str, Any]:
|
@@ -41,12 +47,22 @@ class S2MessageComponent(BaseModel):
|
|
41
47
|
|
42
48
|
@classmethod
|
43
49
|
def from_json(cls, json_str: str) -> Self:
|
44
|
-
|
50
|
+
try:
|
51
|
+
gen_model = cls.model_validate_json(json_str)
|
52
|
+
except (ValidationError, TypeError) as e:
|
53
|
+
raise S2ValidationError(
|
54
|
+
type(cls), cls, "Pydantic raised a validation error.",
|
55
|
+
) from e
|
45
56
|
return gen_model
|
46
57
|
|
47
58
|
@classmethod
|
48
59
|
def from_dict(cls, json_dict: Dict[str, Any]) -> Self:
|
49
|
-
|
60
|
+
try:
|
61
|
+
gen_model = cls.model_validate(json_dict)
|
62
|
+
except (ValidationError, TypeError) as e:
|
63
|
+
raise S2ValidationError(
|
64
|
+
type(cls), cls, "Pydantic raised a validation error.",
|
65
|
+
) from e
|
50
66
|
return gen_model
|
51
67
|
|
52
68
|
|
@@ -61,9 +77,9 @@ def convert_to_s2exception(f: Callable) -> Callable:
|
|
61
77
|
else:
|
62
78
|
class_type = None
|
63
79
|
|
64
|
-
raise S2ValidationError(class_type, args,
|
80
|
+
raise S2ValidationError(class_type, args, str(e)) from e
|
65
81
|
except TypeError as e:
|
66
|
-
raise S2ValidationError(None, args, str(e)
|
82
|
+
raise S2ValidationError(None, args, str(e)) from e
|
67
83
|
|
68
84
|
inner.__doc__ = f.__doc__
|
69
85
|
inner.__annotations__ = f.__annotations__
|
@@ -76,10 +92,5 @@ S = TypeVar("S", bound=S2MessageComponent)
|
|
76
92
|
|
77
93
|
def catch_and_convert_exceptions(input_class: Type[S]) -> Type[S]:
|
78
94
|
input_class.__init__ = convert_to_s2exception(input_class.__init__) # type: ignore[method-assign]
|
79
|
-
input_class.__setattr__ = convert_to_s2exception(input_class.__setattr__) # type: ignore[method-assign]
|
80
|
-
input_class.model_validate_json = convert_to_s2exception( # type: ignore[method-assign]
|
81
|
-
input_class.model_validate_json
|
82
|
-
)
|
83
|
-
input_class.model_validate = convert_to_s2exception(input_class.model_validate) # type: ignore[method-assign]
|
84
95
|
|
85
96
|
return input_class
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|