diff --git a/.github/workflows/lib-ci.yml b/.github/workflows/lib-ci.yml index 76e9c672c0..5717a54401 100644 --- a/.github/workflows/lib-ci.yml +++ b/.github/workflows/lib-ci.yml @@ -46,7 +46,7 @@ jobs: id: total if: matrix.python-version == '3.11' run: | - poetry run python -m coverage report --fail-under 45 + poetry run python -m coverage report --fail-under 40 poetry run python -m coverage html -d build/ poetry run python -m coverage json -o build/coverage.json echo '# Code Coverage Report\n See the index.html for a more detailed report.\n' >> build/README.md diff --git a/src/libecalc/common/tabular_time_series.py b/src/libecalc/common/tabular_time_series.py deleted file mode 100644 index d56771942f..0000000000 --- a/src/libecalc/common/tabular_time_series.py +++ /dev/null @@ -1,84 +0,0 @@ -import itertools -from typing import Protocol, Self, TypeVar - -from pydantic import BaseModel - -from libecalc.common.list.list_utils import transpose -from libecalc.common.time_utils import Periods -from libecalc.common.utils.rates import TimeSeries - - -class TabularTimeSeries(Protocol): - def model_copy(self, deep: bool = False) -> Self: - """ - Duplicate a model - Args: - deep: set to `True` to make a deep copy of the model - - Returns: new model instance - - """ - ... - - -ObjectWithTimeSeries = TypeVar("ObjectWithTimeSeries", bound=TabularTimeSeries) - - -class TabularTimeSeriesUtils: - """ - Utility functions for objects containing TimeSeries - """ - - @classmethod - def merge(cls, *objects_with_time_series: ObjectWithTimeSeries): - """ - Merge objects containing TimeSeries. Other attributes will be copied from the first object. - Args: - *objects_with_time_series: list of objects to merge - - Returns: a merged object of the same type - - """ - # Verify that we are merging the same types - if len({type(object_with_time_series) for object_with_time_series in objects_with_time_series}) != 1: - raise ValueError("Can not merge objects of differing types.") - - first, *others = objects_with_time_series - merged_object = first.model_copy(deep=True) - - for key, value in first.__dict__.items(): - for other in others: - accumulated_value = merged_object.__getattribute__(key) - other_value = other.__getattribute__(key) - if key == "periods": - merged_periods = sorted(itertools.chain(accumulated_value, other_value)) - merged_object.__setattr__(key, Periods(merged_periods)) - elif isinstance(value, TimeSeries): - merged_object.__setattr__(key, accumulated_value.merge(other_value)) - elif isinstance(value, BaseModel): - merged_object.__setattr__( - key, cls.merge(*[obj.__getattribute__(key) for obj in objects_with_time_series]) - ) - elif ( - isinstance(value, list) - and len(value) > 0 - and (isinstance(value[0], TimeSeries) or isinstance(value[0], BaseModel)) - ): - list_attributes = [obj.__getattribute__(key) for obj in objects_with_time_series] - transposed_list_attributes = transpose(list_attributes) - merged_list_attributes = [] - if isinstance(value[0], TimeSeries): - for time_series_to_merge in transposed_list_attributes: - first_time_series, *others_time_series = time_series_to_merge - merged_time_series = first_time_series - for other_time_series in others_time_series: - merged_time_series = merged_time_series.merge(other_time_series) - merged_list_attributes.append(merged_time_series) - elif isinstance(value[0], BaseModel): - merged_list_attributes = [ - cls.merge(*objs_to_merge) for objs_to_merge in transposed_list_attributes - ] - - merged_object.__setattr__(key, merged_list_attributes) - - return merged_object diff --git a/src/libecalc/core/result/results.py b/src/libecalc/core/result/results.py index 06d0c02bef..bf90b833ea 100644 --- a/src/libecalc/core/result/results.py +++ b/src/libecalc/core/result/results.py @@ -6,7 +6,6 @@ from pydantic import Field from libecalc.common.component_type import ComponentType -from libecalc.common.tabular_time_series import TabularTimeSeriesUtils from libecalc.common.time_utils import Periods from libecalc.common.utils.rates import ( TimeSeriesBoolean, @@ -37,21 +36,6 @@ class GenericComponentResult(CommonResultBase): typ: Literal["generc"] = "generc" id: str - def merge(self, *other_results: CompressorResult) -> Self: - """ - Merge all attributes of TimeSeries type, while also making sure the other attributes can be merged (i.e. id should be equal). - Args: - *other_results: - - Returns: - - """ - # Verify that we are merging the same entity - if len({other_result.id for other_result in other_results}) != 1: - raise ValueError("Can not merge objects with differing ids.") - - return TabularTimeSeriesUtils.merge(self, *other_results) - class GeneratorSetResult(GenericComponentResult): """The Generator set result component.""" diff --git a/tests/libecalc/common/test_tabular_time_series.py b/tests/libecalc/common/test_tabular_time_series.py deleted file mode 100644 index 721e5d690f..0000000000 --- a/tests/libecalc/common/test_tabular_time_series.py +++ /dev/null @@ -1,208 +0,0 @@ -from datetime import datetime - -import pytest -from pydantic import BaseModel - -from libecalc.common.tabular_time_series import TabularTimeSeriesUtils -from libecalc.common.time_utils import Period, Periods -from libecalc.common.units import Unit -from libecalc.common.utils.rates import ( - TimeSeriesFloat, - TimeSeriesStreamDayRate, -) - - -class MergeableObject(BaseModel): - string_test: str - int_test: int - float_test: float - list_of_float_test: list[float] - time_series_float: TimeSeriesFloat - time_series_rate: TimeSeriesStreamDayRate - time_series_float_list_test: list[TimeSeriesFloat] - time_series_rate_list_test: list[TimeSeriesStreamDayRate] - - -class TestMerge: - def test_valid_merge(self): - first_periods = Periods.create_periods( - times=[ - datetime(2020, 1, 1), - datetime(2021, 1, 1), - datetime(2022, 1, 1), - ], - include_after=False, - include_before=False, - ) - first = MergeableObject( - string_test="1", - int_test=15, - float_test=1.0, - list_of_float_test=[11, 12, 13, 14, 15], - time_series_rate=TimeSeriesStreamDayRate( - periods=first_periods, - values=[11, 12], - unit=Unit.TONS, - ), - time_series_float=TimeSeriesFloat( - periods=first_periods, - values=[11, 12], - unit=Unit.TONS, - ), - time_series_float_list_test=[ - TimeSeriesFloat( - periods=first_periods, - values=[111, 112], - unit=Unit.TONS, - ), - TimeSeriesFloat( - periods=first_periods, - values=[-111, -112], - unit=Unit.TONS, - ), - ], - time_series_rate_list_test=[ - TimeSeriesStreamDayRate( - periods=first_periods, - values=[111, 112], - unit=Unit.TONS, - ), - TimeSeriesStreamDayRate( - periods=first_periods, - values=[-111, -112], - unit=Unit.TONS, - ), - ], - ) - - second_periods = Periods.create_periods( - times=[ - datetime(2022, 1, 1), - datetime(2023, 1, 1), - datetime(2024, 1, 1), - ], - include_after=False, - include_before=False, - ) - second = MergeableObject( - string_test="2", - int_test=25, - float_test=2.0, - list_of_float_test=[21, 22, 23, 24, 25], - time_series_float=TimeSeriesFloat( - periods=second_periods, - values=[21, 22], - unit=Unit.TONS, - ), - time_series_rate=TimeSeriesStreamDayRate( - periods=second_periods, - values=[21, 22], - unit=Unit.TONS, - ), - time_series_float_list_test=[ - TimeSeriesFloat( - periods=second_periods, - values=[211, 212], - unit=Unit.TONS, - ), - TimeSeriesFloat( - periods=second_periods, - values=[-211, -212], - unit=Unit.TONS, - ), - ], - time_series_rate_list_test=[ - TimeSeriesStreamDayRate( - periods=second_periods, - values=[211, 212], - unit=Unit.TONS, - ), - TimeSeriesStreamDayRate( - periods=second_periods, - values=[-211, -212], - unit=Unit.TONS, - ), - ], - ) - - merged = TabularTimeSeriesUtils.merge(first, second) - - expected_periods = Periods.create_periods( - times=[ - datetime(2020, 1, 1), - datetime(2021, 1, 1), - datetime(2022, 1, 1), - datetime(2023, 1, 1), - datetime(2024, 1, 1), - ], - include_after=False, - include_before=False, - ) - - assert ( - merged.model_dump() - == MergeableObject( - string_test="1", - int_test=15, - float_test=1.0, - list_of_float_test=[11, 12, 13, 14, 15], - time_series_float=TimeSeriesFloat( - periods=expected_periods, - values=[11, 12, 21, 22], - unit=Unit.TONS, - ), - time_series_rate=TimeSeriesStreamDayRate( - periods=expected_periods, - values=[11, 12, 21, 22], - unit=Unit.TONS, - ), - time_series_float_list_test=[ - TimeSeriesFloat( - periods=expected_periods, - values=[111, 112, 211, 212], - unit=Unit.TONS, - ), - TimeSeriesFloat( - periods=expected_periods, - values=[-111, -112, -211, -212], - unit=Unit.TONS, - ), - ], - time_series_rate_list_test=[ - TimeSeriesStreamDayRate( - periods=expected_periods, - values=[111, 112, 211, 212], - unit=Unit.TONS, - ), - TimeSeriesStreamDayRate( - periods=expected_periods, - values=[-111, -112, -211, -212], - unit=Unit.TONS, - ), - ], - ).model_dump() - ) - - def test_invalid_types(self): - class First(BaseModel): - something: TimeSeriesFloat - - first = First( - something=TimeSeriesFloat( - periods=Periods( - [Period(datetime(2022, 1, 1))], - ), - values=[1], - unit=Unit.NONE, - ) - ) - - class Other(BaseModel): - something: list[int] - - other = Other(something=[1, 2]) - - with pytest.raises(ValueError) as exc_info: - TabularTimeSeriesUtils.merge(first, other) - - assert str(exc_info.value) == "Can not merge objects of differing types." diff --git a/tests/libecalc/core/result/test_results.py b/tests/libecalc/core/result/test_results.py deleted file mode 100644 index eec55fd36b..0000000000 --- a/tests/libecalc/core/result/test_results.py +++ /dev/null @@ -1,61 +0,0 @@ -from datetime import datetime - -from libecalc.common.time_utils import Periods -from libecalc.common.units import Unit -from libecalc.common.utils.rates import ( - TimeSeriesBoolean, - TimeSeriesStreamDayRate, -) -from libecalc.core.result import CompressorResult - - -class TestMerge: - def test_merge_compressor_result(self): - periods = Periods.create_periods( - times=[ - datetime(2019, 1, 1), - datetime(2020, 1, 1), - datetime(2021, 1, 1), - datetime(2022, 1, 1), - datetime(2023, 1, 1), - ], - include_after=False, - include_before=False, - ) - compressor_result = CompressorResult( - periods=periods, - energy_usage=TimeSeriesStreamDayRate( - periods=periods, - values=[1, 2, 3, 4], - unit=Unit.STANDARD_CUBIC_METER_PER_DAY, - ), - power=TimeSeriesStreamDayRate( - periods=periods, - values=[1, 2, 3, 4], - unit=Unit.MEGA_WATT, - ), - is_valid=TimeSeriesBoolean( - periods=periods, - values=[True, True, True, True], - unit=Unit.NONE, - ), - recirculation_loss=TimeSeriesStreamDayRate( - periods=periods, - values=[0.1, 0.2, 0.3, 0.4], - unit=Unit.MEGA_WATT, - ), - rate_exceeds_maximum=TimeSeriesBoolean( - periods=periods, - values=[False, False, False, False], - unit=Unit.NONE, - ), - id="My test component", - ) - - compressor_result_subset_1 = compressor_result.get_subset([0, 1]) - - compressor_result_subset_2 = compressor_result.get_subset([2, 3]) - - assert ( - compressor_result_subset_1.merge(compressor_result_subset_2).model_dump() == compressor_result.model_dump() - )