Skip to content

Commit ca36082

Browse files
Rewrite FormulaFormatter.format to format_formula
Signed-off-by: Christian Parpart <[email protected]>
1 parent 4018a59 commit ca36082

File tree

6 files changed

+27
-30
lines changed

6 files changed

+27
-30
lines changed

RELEASE_NOTES.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
- NaN values are treated as missing when gaps are determined in the `OrderedRingBuffer`.
2626

27-
- A new class `FormulaFormatter` has been added to format formulas from `FormulaEngine`. For convenience, `FormulaEngine` now provides an `__str__` override that makes use of this to make formulas more intuitively introspectible.
27+
- Now when printing `FormulaEngine` for debugging purposes the the formula will be shown in infix notation, which should be easier to read.
2828

2929
## Bug Fixes
3030

src/frequenz/sdk/timeseries/_formula_engine/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,11 @@
44
"""A formula engine for applying formulas."""
55
from ._formula_engine import FormulaEngine, FormulaEngine3Phase
66
from ._formula_engine_pool import FormulaEnginePool
7-
from ._formula_formatter import FormulaFormatter
87
from ._resampled_formula_builder import ResampledFormulaBuilder
98

109
__all__ = [
1110
"FormulaEngine",
1211
"FormulaEngine3Phase",
1312
"FormulaEnginePool",
14-
"FormulaFormatter",
1513
"ResampledFormulaBuilder",
1614
]

src/frequenz/sdk/timeseries/_formula_engine/_formula_engine.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from .. import Sample, Sample3Phase
2121
from .._quantities import Quantity, QuantityT
2222
from ._formula_evaluator import FormulaEvaluator
23-
from ._formula_formatter import FormulaFormatter
23+
from ._formula_formatter import format_formula
2424
from ._formula_steps import (
2525
Adder,
2626
Averager,
@@ -318,7 +318,7 @@ def __str__(self) -> str:
318318
if len(self._builder._build_stack) > 0
319319
else self._builder._steps
320320
)
321-
return FormulaFormatter.format(steps)
321+
return format_formula(steps)
322322

323323
def new_receiver(
324324
self, name: str | None = None, max_size: int = 50
@@ -642,7 +642,7 @@ def __str__(self) -> str:
642642
A string representation of the formula.
643643
"""
644644
steps = self._steps if len(self._steps) > 0 else self._build_stack
645-
return FormulaFormatter.format(steps)
645+
return format_formula(steps)
646646

647647
def build(self) -> FormulaEngine[QuantityT]:
648648
"""Create a formula engine with the steps and fetchers that have been pushed.

src/frequenz/sdk/timeseries/_formula_engine/_formula_formatter.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -179,20 +179,7 @@ def __init__(self) -> None:
179179
"""Initialize the FormulaFormatter."""
180180
self._stack = list[StackItem]()
181181

182-
@classmethod
183-
def format(cls, postfix_expr: list[FormulaStep]) -> str:
184-
"""Return the formula as a string in infix notation.
185-
186-
Args:
187-
postfix_expr: The steps of the formula in postfix notation order.
188-
189-
Returns:
190-
str: The formula in infix notation.
191-
"""
192-
formatter = FormulaFormatter()
193-
return formatter._format(postfix_expr)
194-
195-
def _format(self, postfix_expr: list[FormulaStep]) -> str:
182+
def format(self, postfix_expr: list[FormulaStep]) -> str:
196183
"""Format the postfix expression to infix notation.
197184
198185
Args:
@@ -216,7 +203,7 @@ def _format(self, postfix_expr: list[FormulaStep]) -> str:
216203
case Averager():
217204
value = (
218205
# pylint: disable=protected-access
219-
f"avg({', '.join(self._format([f]) for f in step.fetchers)})"
206+
f"avg({', '.join(self.format([f]) for f in step.fetchers)})"
220207
)
221208
self._stack.append(StackItem(value, OperatorPrecedence.PRIMARY, 1))
222209
case Clipper():
@@ -270,3 +257,16 @@ def _pop_two_from_stack(self) -> tuple[StackItem, StackItem]:
270257
right = self._stack.pop()
271258
left = self._stack.pop()
272259
return left, right
260+
261+
262+
def format_formula(postfix_expr: list[FormulaStep]) -> str:
263+
"""Return the formula as a string in infix notation.
264+
265+
Args:
266+
postfix_expr: The steps of the formula in postfix notation order.
267+
268+
Returns:
269+
str: The formula in infix notation.
270+
"""
271+
formatter = FormulaFormatter()
272+
return formatter.format(postfix_expr)

src/frequenz/sdk/timeseries/_formula_engine/_formula_steps.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import math
99
from abc import ABC, abstractmethod
10-
from typing import Generic, Optional, Sequence
10+
from typing import Generic, Sequence
1111

1212
from frequenz.channels import Receiver
1313

tests/timeseries/test_formula_formatter.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@
44
"""Tests for the FormulaFormatter."""
55

66

7-
import logging
8-
97
from frequenz.channels import Broadcast
108
from pytest_mock import MockerFixture
119

1210
from frequenz.sdk import microgrid
1311
from frequenz.sdk.timeseries import Sample
1412
from frequenz.sdk.timeseries._formula_engine._formula_engine import FormulaBuilder
15-
from frequenz.sdk.timeseries._formula_engine._formula_formatter import FormulaFormatter
13+
from frequenz.sdk.timeseries._formula_engine._formula_formatter import format_formula
1614
from frequenz.sdk.timeseries._formula_engine._formula_steps import (
1715
Averager,
1816
Clipper,
@@ -25,6 +23,7 @@
2523
from frequenz.sdk.timeseries._quantities import Percentage, Quantity
2624
from tests.timeseries.mock_microgrid import MockMicrogrid
2725

26+
2827
def build_formula(formula: str) -> list[FormulaStep]:
2928
"""Parse the formula and returns the steps.
3029
@@ -63,7 +62,7 @@ def reconstruct(formula: str) -> str:
6362
The reconstructed formula in infix notation.
6463
"""
6564
steps = build_formula(formula)
66-
reconstructed = FormulaFormatter.format(steps)
65+
reconstructed = format_formula(steps)
6766
if formula != reconstructed:
6867
print(f"Formula: input {formula} != output {reconstructed}")
6968
return reconstructed
@@ -106,16 +105,16 @@ def test_functions(self) -> None:
106105
# For simplicity, we only test with constant values.
107106
# fmt: off
108107
# flake8: noqa: E501
109-
assert FormulaFormatter.format([ConstantValue(2), ConstantValue(3), Minimizer()]) == "min(2, 3)"
110-
assert FormulaFormatter.format([ConstantValue(2), ConstantValue(3), Maximizer()]) == "max(2, 3)"
111-
assert FormulaFormatter.format([ConstantValue(3.5), Clipper(0.0, 1.0)]) == "clip(0.0, 3.5, 1.0)"
108+
assert format_formula([ConstantValue(2), ConstantValue(3), Minimizer()]) == "min(2, 3)"
109+
assert format_formula([ConstantValue(2), ConstantValue(3), Maximizer()]) == "max(2, 3)"
110+
assert format_formula([ConstantValue(3.5), Clipper(0.0, 1.0)]) == "clip(0.0, 3.5, 1.0)"
112111
# flake8: enable
113112
# fmt: on
114113

115114
def test_function_avg(self) -> None:
116115
"""Test that the avg function is formatted correctly."""
117116
# This tests the special case of the avg function with no arguments.
118-
assert FormulaFormatter.format([Averager[Percentage]([])]) == "avg()"
117+
assert format_formula([Averager[Percentage]([])]) == "avg()"
119118

120119
async def test_higher_order_formula(self, mocker: MockerFixture) -> None:
121120
"""Test that the formula is formatted correctly for a higher-order formula."""

0 commit comments

Comments
 (0)