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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: s2-python
3
- Version: 0.6.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.6.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
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=uYR-8yTzqyf7xerX7ULk6prm7_Cc5h_2EC9CGCKHIJM,4583
9
- s2python/s2_validation_error.py,sha256=paWJAkmjOwigeFmF8Zwo-5ithRJ2SRqOLX-rHRZ6ces,398
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=AsycGNUjH9oMAYdOXgJR1QelyNEiM31Cp0HpBzenMxU,2539
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=Uy0dOe6Lo_WEswS8pHHZXSeC5UnrrwpYb8R7NENNUKQ,1606
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=4c6OEIG9-75M9aiqmvUUWMwGkAkQEVGRcVvi_Iz6mlk,1486
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=-jpw1ccIrV1-DkgH4pbvihheRBTDZt79l5Lsn89HAsc,856
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=mPUfow7sEw8uzvMRZaBNnmmHOzjFsv1CtIFCNrXAhXs,1095
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.6.0.dist-info/METADATA,sha256=Yn_Nam6WQGtdbU6a92XiXK7hXjzOwV8xlX4aJcbZUJ8,3814
86
- s2_python-0.6.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
87
- s2_python-0.6.0.dist-info/entry_points.txt,sha256=feX-xmgJZgSe5-jxMgFKPKCJz4Ys3eQcGrsXsirNZyM,61
88
- s2_python-0.6.0.dist-info/top_level.txt,sha256=OLFq0oDhr77Mp-EYLEcWk5P3jvooOt4IHkTI5KYJMc8,9
89
- s2_python-0.6.0.dist-info/RECORD,,
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: dict[CommodityQuantity, bool] = {}
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: dict[CommodityQuantity, bool] = {}
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].model_validate(message_json)
93
+ return TYPE_TO_MESSAGE_CLASS[message_type].from_dict(message_json)
95
94
 
96
95
  @staticmethod
97
96
  def parse_as_message(
@@ -1,8 +1,5 @@
1
1
  from dataclasses import dataclass
2
- from typing import Union, Type, Optional
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 format validation error.", e
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
- gen_model = cls.model_validate_json(json_str)
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
- gen_model = cls.model_validate(json_dict)
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, display_errors(e.errors()), e) from e # type: ignore[arg-type]
80
+ raise S2ValidationError(class_type, args, str(e)) from e
65
81
  except TypeError as e:
66
- raise S2ValidationError(None, args, str(e), e) from 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