Skip to content

Commit

Permalink
refactor: move generator to formatter
Browse files Browse the repository at this point in the history
Move the generator functionality to formatter as an index formatter.
  • Loading branch information
jsolaas committed Oct 21, 2024
1 parent 9f2aa1a commit 0937014
Show file tree
Hide file tree
Showing 10 changed files with 113 additions and 132 deletions.
5 changes: 4 additions & 1 deletion src/ecalc_cli/io/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from libecalc.dto import Asset, ResultOptions
from libecalc.infrastructure.file_utils import OutputFormat, get_result_output
from libecalc.presentation.exporter.configs.configs import LTPConfig, STPConfig
from libecalc.presentation.exporter.configs.formatter_config import TimeFormatterConfig
from libecalc.presentation.exporter.exporter import Exporter
from libecalc.presentation.exporter.formatters.formatter import CSVFormatter
from libecalc.presentation.exporter.handlers.handler import MultiFileHandler
Expand Down Expand Up @@ -155,7 +156,9 @@ def export_tsv(
prognosis_filter = config.filter(frequency=frequency)
result = prognosis_filter.filter(ExportableGraphResult(results), resampled_timevector)

row_based_data: Dict[str, List[str]] = CSVFormatter(separation_character="\t").format_groups(result)
row_based_data: Dict[str, List[str]] = CSVFormatter(
separation_character="\t", index_formatters=TimeFormatterConfig.get_row_index_formatters()
).format_groups(result)

exporter = Exporter()
exporter.add_handler(
Expand Down
43 changes: 0 additions & 43 deletions src/libecalc/presentation/exporter/configs/configs.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import abc
from typing import List

from libecalc.common.time_utils import Frequency
from libecalc.common.units import Unit
Expand All @@ -13,7 +12,6 @@
InvertValuesModifier,
)
from libecalc.presentation.exporter.filters import Filter
from libecalc.presentation.exporter.generators import Generator, TimeIndexGenerator
from libecalc.presentation.exporter.queries import (
ElectricityGeneratedQuery,
EmissionQuery,
Expand All @@ -30,15 +28,6 @@


class ResultConfig(abc.ABC):
@staticmethod
@abc.abstractmethod
def generators() -> List[Generator]:
"""Currently we consider every config to relate to _one_ time vector, representing
the resolution/frequency of all data provided by all appliers for a given aggregation...
:return:
"""
pass

@staticmethod
@abc.abstractmethod
def aggregator(frequency: Frequency) -> Aggregator:
Expand All @@ -59,25 +48,9 @@ class LTPConfig(ResultConfig):
@staticmethod
def filter(frequency: Frequency) -> Filter:
return Filter(
generators=LTPConfig.generators(),
aggregator=LTPConfig.aggregator(frequency=frequency),
)

@staticmethod
def generators() -> List[Generator]:
return [
TimeIndexGenerator(
name="forecastYear",
title="Years",
time_format="%Y",
),
TimeIndexGenerator(
name="forecastMonth",
title="Months",
time_format="%m",
),
]

@staticmethod
def aggregator(frequency: Frequency) -> Aggregator:
return InstallationAggregator(
Expand Down Expand Up @@ -683,25 +656,9 @@ class STPConfig(ResultConfig):
@staticmethod
def filter(frequency: Frequency) -> Filter:
return Filter(
generators=STPConfig.generators(),
aggregator=STPConfig.aggregator(frequency=frequency),
)

@staticmethod
def generators() -> List[Generator]:
return [
TimeIndexGenerator(
name="forecastYear",
title="Years",
time_format="%Y",
),
TimeIndexGenerator(
name="forecastMonth",
title="Months",
time_format="%m",
),
]

@staticmethod
def aggregator(frequency: Frequency) -> Aggregator:
return InstallationAggregator(
Expand Down
28 changes: 28 additions & 0 deletions src/libecalc/presentation/exporter/configs/formatter_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import abc
from typing import List

from libecalc.presentation.exporter.formatters.formatter import IndexFormatter
from libecalc.presentation.exporter.formatters.index_formatter import TimeIndexFormatter


class FormatterConfig(abc.ABC):
@staticmethod
@abc.abstractmethod
def get_row_index_formatters() -> List[IndexFormatter]: ...


class TimeFormatterConfig(FormatterConfig):
@staticmethod
def get_row_index_formatters() -> List[IndexFormatter]:
return [
TimeIndexFormatter(
name="forecastYear",
title="Years",
time_format="%Y",
),
TimeIndexFormatter(
name="forecastMonth",
title="Months",
time_format="%m",
),
]
27 changes: 5 additions & 22 deletions src/libecalc/presentation/exporter/dto/dtos.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,7 @@

from libecalc.common.units import Unit
from libecalc.domain.tabular.exceptions import ColumnNotFound
from libecalc.presentation.exporter.formatters.formatter import (
ColumnIndex,
Formattable,
FormattableGroup,
RowIndex,
)
from libecalc.presentation.exporter.formatters.formattable import ColumnIndex, Formattable, FormattableGroup, RowIndex


@dataclass
Expand Down Expand Up @@ -57,7 +52,6 @@ class GroupedQueryResult:

@dataclass
class FormattableGroupedQuery(Formattable):
data_series: List[DataSeries]
query_results: List[QueryResult]
time_vector: List[datetime]

Expand All @@ -68,33 +62,23 @@ def row_ids(self) -> List[RowIndex]:
@property
def column_ids(self) -> List[ColumnIndex]:
column_ids = []
for data_serie in self.data_series:
column_ids.append(data_serie.id)
for query_result in self.query_results:
column_ids.append(query_result.id)
return column_ids

def get_column(self, column_id: ColumnIndex) -> Union[DataSeries, QueryResult]:
try:
return next(data_serie for data_serie in self.data_series if data_serie.id == column_id)
except StopIteration:
try:
return next(query_result for query_result in self.query_results if query_result.id == column_id)
except StopIteration as e:
raise ColumnNotFound(column_id) from e
return next(query_result for query_result in self.query_results if query_result.id == column_id)
except StopIteration as e:
raise ColumnNotFound(column_id) from e

def get_value(self, row_id: RowIndex, column_id: ColumnIndex) -> Union[int, float]:
column = self.get_column(column_id)
if isinstance(column, DataSeries):
index = self.row_ids.index(row_id)
return column.values[index]
else:
return column.values[row_id]
return column.values[row_id]


@dataclass
class FilteredResult(FormattableGroup):
data_series: List[DataSeries]
query_results: List[GroupedQueryResult]
time_vector: List[datetime]

Expand All @@ -104,7 +88,6 @@ def groups(self) -> Iterator[Tuple[str, Formattable]]:
(
group.group_name,
FormattableGroupedQuery(
data_series=self.data_series,
time_vector=self.time_vector,
query_results=group.query_results,
),
Expand Down
11 changes: 1 addition & 10 deletions src/libecalc/presentation/exporter/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from libecalc.presentation.exporter.aggregators import Aggregator
from libecalc.presentation.exporter.domain.exportable import ExportableSet
from libecalc.presentation.exporter.dto.dtos import FilteredResult
from libecalc.presentation.exporter.generators import Generator


@dataclass
Expand All @@ -14,11 +13,6 @@ class Filter:
the complete result object.
"""

generators: List[Generator]
"""
The index all the data relate to is a bit special...
"""

aggregator: Aggregator
"""
Currently only one type of aggregator can be used, since we cannot deal with different levels of aggregators
Expand All @@ -30,9 +24,6 @@ def filter(
energy_calculator_result: ExportableSet,
time_vector: List[datetime],
) -> FilteredResult:
data_series_collection = [generator.generate(time_vector) for generator in self.generators]
query_result_collection = self.aggregator.aggregate(energy_calculator_result)

return FilteredResult(
data_series=data_series_collection, query_results=query_result_collection, time_vector=time_vector
)
return FilteredResult(query_results=query_result_collection, time_vector=time_vector)
18 changes: 18 additions & 0 deletions src/libecalc/presentation/exporter/formatters/formattable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import abc
from datetime import datetime
from typing import Iterator, Protocol, Tuple, Union

from libecalc.domain.tabular.tabular import HasColumns, Tabular


class Formattable(Tabular, HasColumns, Protocol): ...


class FormattableGroup(Protocol):
@property
@abc.abstractmethod
def groups(self) -> Iterator[Tuple[str, Formattable]]: ...


RowIndex = Union[str, int, float, datetime]
ColumnIndex = Union[str]
35 changes: 16 additions & 19 deletions src/libecalc/presentation/exporter/formatters/formatter.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,8 @@
import abc
from datetime import datetime
from typing import Dict, Iterator, List, Protocol, Tuple, Union
from typing import Dict, List

from libecalc.domain.tabular.tabular import HasColumns, Tabular

RowIndex = Union[str, int, float, datetime]
ColumnIndex = Union[str]


class Formattable(Tabular, HasColumns, Protocol): ...


class FormattableGroup(Protocol):
@property
@abc.abstractmethod
def groups(self) -> Iterator[Tuple[str, Formattable]]: ...
from libecalc.presentation.exporter.formatters.formattable import Formattable, FormattableGroup
from libecalc.presentation.exporter.formatters.index_formatter import IndexFormatter


class Formatter(abc.ABC):
Expand All @@ -31,20 +19,29 @@ def format_group(self, groups: FormattableGroup) -> Dict[str, List[str]]: ...


class CSVFormatter:
def __init__(self, separation_character: str = ","):
def __init__(self, separation_character: str = ",", index_formatters: List[IndexFormatter] = None):
self.separation_character = separation_character
self.index_formatters = index_formatters or []

def format(self, tabular: Formattable) -> List[str]:
column_ids = tabular.column_ids
rows: List[str] = [
self.separation_character.join(list(column_ids)),
self.separation_character.join(
[*[index_formatter.get_id() for index_formatter in self.index_formatters], *column_ids]
),
"#"
+ self.separation_character.join([tabular.get_column(column_id).get_title() for column_id in column_ids]),
+ self.separation_character.join(
[
*[index_formatter.get_title() for index_formatter in self.index_formatters],
*[tabular.get_column(column_id).get_title() for column_id in column_ids],
]
),
]

for row_id in tabular.row_ids:
row_index = [index_formatter.format(row_id) for index_formatter in self.index_formatters]
row = [str(tabular.get_value(row_id, column_id)) for column_id in column_ids]
rows.append(self.separation_character.join(row))
rows.append(self.separation_character.join([*row_index, *row]))
return rows

def format_groups(self, grouped_tabular: FormattableGroup) -> Dict[str, List[str]]:
Expand Down
40 changes: 40 additions & 0 deletions src/libecalc/presentation/exporter/formatters/index_formatter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import abc
from datetime import datetime

from libecalc.presentation.exporter.formatters.formattable import RowIndex


class IndexFormatter(abc.ABC):
"""
Index formatter can be used to format the index in a Formatter
"""

@abc.abstractmethod
def format(self, index: RowIndex) -> str: ...

@abc.abstractmethod
def get_title(self) -> str: ...

@abc.abstractmethod
def get_id(self) -> str: ...


class TimeIndexFormatter(IndexFormatter):
def __init__(
self,
name: str,
title: str,
time_format: str,
):
self.name = name
self.title = title
self.time_format = time_format

def get_id(self) -> str:
return self.name

def get_title(self) -> str:
return self.title

def format(self, index: datetime) -> str:
return datetime.strftime(index, self.time_format)
36 changes: 0 additions & 36 deletions src/libecalc/presentation/exporter/generators.py

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

from libecalc.common.units import Unit
from libecalc.domain.tabular.tabular import ColumnIndex
from libecalc.presentation.exporter.formatters.formattable import Formattable
from libecalc.presentation.exporter.formatters.formatter import (
CSVFormatter,
Formattable,
)


Expand Down

0 comments on commit 0937014

Please sign in to comment.