From 3604c2e4fdbe81453e5df44e5cef926004b2bf6a Mon Sep 17 00:00:00 2001 From: Victor Garcia Reolid Date: Fri, 8 Sep 2023 16:36:46 +0200 Subject: [PATCH 1/3] adapt code to work in Python 3.8 Signed-off-by: Victor Garcia Reolid --- .github/workflows/ci.yml | 7 +-- src/s2python/common/number_range.py | 4 +- src/s2python/common/power_range.py | 4 +- src/s2python/common/support.py | 31 +++++++------ .../frbc/frbc_actuator_description.py | 14 +++--- src/s2python/frbc/frbc_operation_mode.py | 10 ++--- src/s2python/utils.py | 3 ++ src/s2python/validate_values_mixin.py | 6 +-- tests/unit/utils_test.py | 44 +++++++++++++++++++ tox.ini | 1 + 10 files changed, 86 insertions(+), 38 deletions(-) create mode 100644 src/s2python/utils.py create mode 100644 tests/unit/utils_test.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 029ff8f..452c291 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: with: {fetch-depth: 0} # deep clone for setuptools-scm - uses: actions/setup-python@v4 id: setup-python - with: {python-version: "3.11"} + with: {python-version: "3.8"} # - name: Run static analysis and format checkers # run: pipx run pre-commit run --all-files --show-diff-on-failure - name: Build package distribution files @@ -55,8 +55,9 @@ jobs: strategy: matrix: python: - # - "3.9" - # - "3.7" # oldest Python supported by PSF + - "3.8" + - "3.9" + - "3.10" - "3.11" # newest Python that is stable platform: - ubuntu-latest diff --git a/src/s2python/common/number_range.py b/src/s2python/common/number_range.py index c17cc70..b181342 100644 --- a/src/s2python/common/number_range.py +++ b/src/s2python/common/number_range.py @@ -1,4 +1,4 @@ -from typing import Any +from typing import Any, Dict from pydantic import root_validator @@ -11,7 +11,7 @@ class Config(GenNumberRange.Config): validate_assignment = True @root_validator(pre=False) - def validate_start_end_order(cls, values: dict[str, Any]) -> dict[str, Any]: + def validate_start_end_order(cls, values: Dict[str, Any]) -> Dict[str, Any]: if values.get("start_of_range", 0.0) > values.get("end_of_range", 0.0): raise ValueError(cls, 'start_of_range should not be higher than end_of_range') diff --git a/src/s2python/common/power_range.py b/src/s2python/common/power_range.py index 2b87173..9cb74b2 100644 --- a/src/s2python/common/power_range.py +++ b/src/s2python/common/power_range.py @@ -1,4 +1,4 @@ -from typing import Any +from typing import Any, Dict from pydantic import root_validator @@ -12,7 +12,7 @@ class Config(GenPowerRange.Config): validate_assignment = True @root_validator(pre=False) - def validate_start_end_order(cls, values: dict[str, Any]) -> dict[str, Any]: + def validate_start_end_order(cls, values: Dict[str, Any]) -> Dict[str, Any]: if values.get("start_of_range", 0.0) > values.get("end_of_range", 0.0): raise ValueError(cls, 'start_of_range should not be higher than end_of_range') diff --git a/src/s2python/common/support.py b/src/s2python/common/support.py index 3b676ab..eed2592 100644 --- a/src/s2python/common/support.py +++ b/src/s2python/common/support.py @@ -2,19 +2,18 @@ def commodity_has_quantity(commodity: 'Commodity', quantity: CommodityQuantity) -> bool: - match commodity: - case Commodity.HEAT: - return quantity in [CommodityQuantity.HEAT_THERMAL_POWER, - CommodityQuantity.HEAT_TEMPERATURE, - CommodityQuantity.HEAT_FLOW_RATE] - case Commodity.ELECTRICITY: - return quantity in [CommodityQuantity.ELECTRIC_POWER_3_PHASE_SYMMETRIC, - CommodityQuantity.ELECTRIC_POWER_L1, - CommodityQuantity.ELECTRIC_POWER_L2, - CommodityQuantity.ELECTRIC_POWER_L3] - case Commodity.GAS: - return quantity in [CommodityQuantity.NATURAL_GAS_FLOW_RATE] - case Commodity.OIL: - return quantity in [CommodityQuantity.OIL_FLOW_RATE] - case _: - raise RuntimeError(f'Unsupported commodity {commodity}. Missing implementation.') + if commodity == Commodity.HEAT: + return quantity in [CommodityQuantity.HEAT_THERMAL_POWER, + CommodityQuantity.HEAT_TEMPERATURE, + CommodityQuantity.HEAT_FLOW_RATE] + elif commodity == Commodity.ELECTRICITY: + return quantity in [CommodityQuantity.ELECTRIC_POWER_3_PHASE_SYMMETRIC, + CommodityQuantity.ELECTRIC_POWER_L1, + CommodityQuantity.ELECTRIC_POWER_L2, + CommodityQuantity.ELECTRIC_POWER_L3] + elif commodity == Commodity.GAS: + return quantity in [CommodityQuantity.NATURAL_GAS_FLOW_RATE] + elif commodity == Commodity.OIL: + return quantity in [CommodityQuantity.OIL_FLOW_RATE] + else: + raise RuntimeError(f'Unsupported commodity {commodity}. Missing implementation.') diff --git a/src/s2python/frbc/frbc_actuator_description.py b/src/s2python/frbc/frbc_actuator_description.py index 62443bc..3fda1d2 100644 --- a/src/s2python/frbc/frbc_actuator_description.py +++ b/src/s2python/frbc/frbc_actuator_description.py @@ -1,6 +1,6 @@ import uuid -from typing import List, Any +from typing import List, Any, Dict from pydantic import root_validator @@ -23,7 +23,7 @@ class Config(GenFRBCActuatorDescription.Config): supported_commodities: List[Commodity] = GenFRBCActuatorDescription.__fields__['supported_commodities'].field_info # type: ignore[assignment] @root_validator(pre=False) - def validate_timers_in_transitions(cls, values: dict[str, Any]) -> dict[str, Any]: + def validate_timers_in_transitions(cls, values: Dict[str, Any]) -> Dict[str, Any]: timers_by_id = {timer.id: timer for timer in values.get("timers", {})} transition: Transition for transition in values.get("transitions", []): @@ -40,7 +40,7 @@ def validate_timers_in_transitions(cls, values: dict[str, Any]) -> dict[str, Any return values @root_validator(pre=False) - def validate_timers_unique_ids(cls, values: dict[str, Any]) -> dict[str, Any]: + def validate_timers_unique_ids(cls, values: Dict[str, Any]) -> Dict[str, Any]: ids = [] timer: Timer for timer in values.get("timers", []): @@ -51,7 +51,7 @@ def validate_timers_unique_ids(cls, values: dict[str, Any]) -> dict[str, Any]: return values @root_validator(pre=False) - def validate_operation_modes_in_transitions(cls, values: dict[str, Any]) -> dict[str, Any]: + def validate_operation_modes_in_transitions(cls, values: Dict[str, Any]) -> Dict[str, Any]: operation_mode_by_id = {operation_mode.id: operation_mode for operation_mode in values.get("operation_modes", [])} transition: Transition @@ -67,7 +67,7 @@ def validate_operation_modes_in_transitions(cls, values: dict[str, Any]) -> dict return values @root_validator(pre=False) - def validate_operation_modes_unique_ids(cls, values: dict[str, Any]) -> dict[str, Any]: + def validate_operation_modes_unique_ids(cls, values: Dict[str, Any]) -> Dict[str, Any]: ids = [] operation_mode: FRBCOperationMode for operation_mode in values.get("operation_modes", []): @@ -78,7 +78,7 @@ def validate_operation_modes_unique_ids(cls, values: dict[str, Any]) -> dict[str return values @root_validator(pre=False) - def validate_operation_mode_elements_have_all_supported_commodities(cls, values: dict[str, Any]) -> dict[str, Any]: + def validate_operation_mode_elements_have_all_supported_commodities(cls, values: Dict[str, Any]) -> Dict[str, Any]: supported_commodities = values.get('supported_commodities', []) operation_mode: FRBCOperationMode for operation_mode in values.get("operation_modes", []): @@ -99,7 +99,7 @@ def validate_operation_mode_elements_have_all_supported_commodities(cls, values: return values @root_validator(pre=False) - def validate_unique_supported_commodities(cls, values: dict[str, Any]) -> dict[str, Any]: + def validate_unique_supported_commodities(cls, values: Dict[str, Any]) -> Dict[str, Any]: supported_commodities: list[CommodityQuantity] = values.get('supported_commodities', []) for supported_commodity in supported_commodities: diff --git a/src/s2python/frbc/frbc_operation_mode.py b/src/s2python/frbc/frbc_operation_mode.py index 1df1230..f2f5a7d 100644 --- a/src/s2python/frbc/frbc_operation_mode.py +++ b/src/s2python/frbc/frbc_operation_mode.py @@ -1,6 +1,6 @@ -from itertools import pairwise +#from itertools import pairwise import uuid -from typing import List, Dict, Any +from typing import List, Dict, Any, Generator, Tuple from pydantic import root_validator @@ -8,7 +8,7 @@ from s2python.frbc import FRBCOperationModeElement from s2python.generated.gen_s2 import FRBCOperationMode as GenFRBCOperationMode from s2python.validate_values_mixin import ValidateValuesMixin, catch_and_convert_exceptions - +from s2python.utils import pairwise @catch_and_convert_exceptions class FRBCOperationMode(GenFRBCOperationMode, ValidateValuesMixin['FRBCOperationMode']): @@ -19,11 +19,11 @@ class Config(GenFRBCOperationMode.Config): elements: List[FRBCOperationModeElement] = GenFRBCOperationMode.__fields__['elements'].field_info # type: ignore[assignment] @root_validator(pre=False) - def validate_contiguous_fill_levels_operation_mode_elements(cls, values: dict[str, Any]) -> dict[str, Any]: + def validate_contiguous_fill_levels_operation_mode_elements(cls, values: Dict[str, Any]) -> Dict[str, Any]: elements_by_fill_level_range: Dict[NumberRange, FRBCOperationModeElement] elements_by_fill_level_range = {element.fill_level_range: element for element in values.get('elements', [])} - sorted_fill_level_ranges: list[NumberRange] + sorted_fill_level_ranges: List[NumberRange] sorted_fill_level_ranges = list(elements_by_fill_level_range.keys()) sorted_fill_level_ranges.sort(key=lambda r: r.start_of_range) diff --git a/src/s2python/utils.py b/src/s2python/utils.py new file mode 100644 index 0000000..bc0a970 --- /dev/null +++ b/src/s2python/utils.py @@ -0,0 +1,3 @@ +def pairwise(arr : list): + for i in range(max(len(arr) - 1,0)): + yield (arr[i], arr[i+1]) diff --git a/src/s2python/validate_values_mixin.py b/src/s2python/validate_values_mixin.py index 16f8ba1..51bd1c6 100644 --- a/src/s2python/validate_values_mixin.py +++ b/src/s2python/validate_values_mixin.py @@ -1,4 +1,4 @@ -from typing import TypeVar, Generic, Protocol, Type, Tuple, Optional, Callable, cast, Any, Union, AbstractSet, Mapping +from typing import TypeVar, Generic, Protocol, Type, Tuple, Optional, Callable, cast, Any, Union, AbstractSet, Mapping, List, Dict from pydantic import BaseModel, StrBytes, Protocol as PydanticProtocol, ValidationError @@ -43,7 +43,7 @@ def dict( exclude_unset: bool = False, exclude_defaults: bool = False, exclude_none: bool = False, - ) -> dict[str, Any]: ... + ) -> Dict[str, Any]: ... @classmethod def parse_raw(cls, @@ -75,7 +75,7 @@ def from_json(cls: Type[C], json_str: str) -> C: def convert_to_s2exception(f : Callable) -> Callable: - def inner(*args: list[Any], **kwargs: dict[str, Any]) -> Any: + def inner(*args: List[Any], **kwargs: Dict[str, Any]) -> Any: try: return f(*args, **kwargs) except (ValidationError, TypeError) as e: diff --git a/tests/unit/utils_test.py b/tests/unit/utils_test.py new file mode 100644 index 0000000..e6a5e39 --- /dev/null +++ b/tests/unit/utils_test.py @@ -0,0 +1,44 @@ +from unittest import TestCase + +from s2python.utils import pairwise + +class PairwiseTest(TestCase): + def test_empty(self): + # Arrange + input_array = [] + + # Act + pairs = list(pairwise(input_array)) + + # Assert + self.assertEqual(len(pairs), 0) + + def test_len_2(self): + # Arrange + input_array = [1,2] + + # Act + pairs = list(pairwise(input_array)) + + # Assert + self.assertEqual(pairs, [(1,2)]) + + def test_odd(self): + # Arrange + input_array = [1,2,3] + + # Act + pairs = list(pairwise(input_array)) + + # Assert + self.assertEqual(pairs, [(1,2), (2,3)]) + + def test_even(self): + # Arrange + input_array = [1,2,3,4] + + # Act + pairs = list(pairwise(input_array)) + + # Assert + self.assertEqual(pairs, [(1,2), (2,3), (3,4)]) \ No newline at end of file diff --git a/tox.ini b/tox.ini index fdc4189..561f8d5 100644 --- a/tox.ini +++ b/tox.ini @@ -6,6 +6,7 @@ isolated_build = True [testenv] description = Invoke pytest to run automated tests +basepython = /usr/bin/python3.8 setenv = TOXINIDIR = {toxinidir} passenv = From e40ad07d5eee6afe8da3a87049a3a284891fdd0c Mon Sep 17 00:00:00 2001 From: Victor Garcia Reolid Date: Fri, 8 Sep 2023 16:48:55 +0200 Subject: [PATCH 2/3] change python to 3.11 for tox Signed-off-by: Victor Garcia Reolid --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 452c291..70f176b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: with: {fetch-depth: 0} # deep clone for setuptools-scm - uses: actions/setup-python@v4 id: setup-python - with: {python-version: "3.8"} + with: {python-version: "3.11"} # - name: Run static analysis and format checkers # run: pipx run pre-commit run --all-files --show-diff-on-failure - name: Build package distribution files From 37c70eb94b892840cff93f77ceb5ebe3043def95 Mon Sep 17 00:00:00 2001 From: Victor Garcia Reolid Date: Fri, 8 Sep 2023 16:51:49 +0200 Subject: [PATCH 3/3] again Signed-off-by: Victor Garcia Reolid --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 561f8d5..a84d15f 100644 --- a/tox.ini +++ b/tox.ini @@ -6,7 +6,7 @@ isolated_build = True [testenv] description = Invoke pytest to run automated tests -basepython = /usr/bin/python3.8 + setenv = TOXINIDIR = {toxinidir} passenv =