Skip to content

Commit e2d58f1

Browse files
committed
Remove dependence on _ComposableFormulaEngine in FormulaEngine
`_ComposableFormulaEngine` is a generic class exposing arithmetic methods with typing for single-phase and three-phase formulas. But typing support has been incorrect and incomplete since the beginning. The cleanest solution appears to be to just implement the methods on each of the `FormulaEngine`s separately, so that they can be fully typed. Signed-off-by: Sahas Subramanian <[email protected]>
1 parent 99b25ec commit e2d58f1

File tree

1 file changed

+135
-9
lines changed

1 file changed

+135
-9
lines changed

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

Lines changed: 135 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -220,14 +220,7 @@ def production(self) -> _GenericHigherOrderBuilder:
220220
return self._higher_order_builder(self, self._create_method).production() # type: ignore
221221

222222

223-
class FormulaEngine(
224-
Generic[QuantityT],
225-
_ComposableFormulaEngine[
226-
"FormulaEngine", # type: ignore[type-arg]
227-
"HigherOrderFormulaBuilder", # type: ignore[type-arg]
228-
QuantityT,
229-
],
230-
):
223+
class FormulaEngine(Generic[QuantityT]):
231224
"""[`FormulaEngine`][frequenz.sdk.timeseries.formula_engine.FormulaEngine]s are a
232225
part of the SDK's data pipeline, and provide a way for the SDK to apply formulas on
233226
resampled data streams.
@@ -308,8 +301,15 @@ def __init__(
308301
self._higher_order_builder = HigherOrderFormulaBuilder
309302
self._name: str = builder.name
310303
self._builder: FormulaBuilder[QuantityT] = builder
311-
self._create_method = create_method
304+
self._create_method: Callable[[float], QuantityT] = create_method
312305
self._channel: Broadcast[Sample[QuantityT]] = Broadcast(name=self._name)
306+
self._task: asyncio.Task[None] | None = None
307+
308+
async def _stop(self) -> None:
309+
"""Stop a running formula engine."""
310+
if self._task is None:
311+
return
312+
await cancel_and_await(self._task)
313313

314314
@classmethod
315315
def from_receiver(
@@ -366,6 +366,132 @@ async def run() -> None:
366366
builder.push_metric(name, receiver, nones_are_zeros=nones_are_zeros)
367367
return cls(builder, create_method)
368368

369+
def __add__(
370+
self,
371+
other: (
372+
FormulaEngine[QuantityT] | HigherOrderFormulaBuilder[QuantityT] | QuantityT
373+
),
374+
) -> HigherOrderFormulaBuilder[QuantityT]:
375+
"""Return a formula builder that adds (data in) `other` to `self`.
376+
377+
Args:
378+
other: A formula receiver, or a formula builder instance corresponding to a
379+
sub-expression.
380+
381+
Returns:
382+
A formula builder that can take further expressions, or can be built
383+
into a formula engine.
384+
"""
385+
return HigherOrderFormulaBuilder(self, self._create_method) + other
386+
387+
def __sub__(
388+
self,
389+
other: (
390+
FormulaEngine[QuantityT] | HigherOrderFormulaBuilder[QuantityT] | QuantityT
391+
),
392+
) -> HigherOrderFormulaBuilder[QuantityT]:
393+
"""Return a formula builder that subtracts (data in) `other` from `self`.
394+
395+
Args:
396+
other: A formula receiver, or a formula builder instance corresponding to a
397+
sub-expression.
398+
399+
Returns:
400+
A formula builder that can take further expressions, or can be built
401+
into a formula engine.
402+
"""
403+
return HigherOrderFormulaBuilder(self, self._create_method) - other
404+
405+
def __mul__(
406+
self,
407+
other: FormulaEngine[QuantityT] | HigherOrderFormulaBuilder[QuantityT] | float,
408+
) -> HigherOrderFormulaBuilder[QuantityT]:
409+
"""Return a formula builder that multiplies (data in) `self` with `other`.
410+
411+
Args:
412+
other: A formula receiver, or a formula builder instance corresponding to a
413+
sub-expression.
414+
415+
Returns:
416+
A formula builder that can take further expressions, or can be built
417+
into a formula engine.
418+
"""
419+
return HigherOrderFormulaBuilder(self, self._create_method) * other
420+
421+
def __truediv__(
422+
self,
423+
other: FormulaEngine[QuantityT] | HigherOrderFormulaBuilder[QuantityT] | float,
424+
) -> HigherOrderFormulaBuilder[QuantityT]:
425+
"""Return a formula builder that divides (data in) `self` by `other`.
426+
427+
Args:
428+
other: A formula receiver, or a formula builder instance corresponding to a
429+
sub-expression.
430+
431+
Returns:
432+
A formula builder that can take further expressions, or can be built
433+
into a formula engine.
434+
"""
435+
return HigherOrderFormulaBuilder(self, self._create_method) / other
436+
437+
def max(
438+
self,
439+
other: (
440+
FormulaEngine[QuantityT] | HigherOrderFormulaBuilder[QuantityT] | QuantityT
441+
),
442+
) -> HigherOrderFormulaBuilder[QuantityT]:
443+
"""Return a formula engine that outputs the maximum of `self` and `other`.
444+
445+
Args:
446+
other: A formula receiver, a formula builder or a QuantityT instance
447+
corresponding to a sub-expression.
448+
449+
Returns:
450+
A formula builder that can take further expressions, or can be built
451+
into a formula engine.
452+
"""
453+
return HigherOrderFormulaBuilder(self, self._create_method).max(other)
454+
455+
def min(
456+
self,
457+
other: (
458+
FormulaEngine[QuantityT] | HigherOrderFormulaBuilder[QuantityT] | QuantityT
459+
),
460+
) -> HigherOrderFormulaBuilder[QuantityT]:
461+
"""Return a formula engine that outputs the minimum of `self` and `other`.
462+
463+
Args:
464+
other: A formula receiver, a formula builder or a QuantityT instance
465+
corresponding to a sub-expression.
466+
467+
Returns:
468+
A formula builder that can take further expressions, or can be built
469+
into a formula engine.
470+
"""
471+
return HigherOrderFormulaBuilder(self, self._create_method).min(other)
472+
473+
def consumption(
474+
self,
475+
) -> HigherOrderFormulaBuilder[QuantityT]:
476+
"""
477+
Return a formula builder that applies the consumption operator on `self`.
478+
479+
The consumption operator returns either the identity if the power value is
480+
positive or 0.
481+
"""
482+
return HigherOrderFormulaBuilder(self, self._create_method).consumption()
483+
484+
def production(
485+
self,
486+
) -> HigherOrderFormulaBuilder[QuantityT]:
487+
"""
488+
Return a formula builder that applies the production operator on `self`.
489+
490+
The production operator returns either the absolute value if the power value is
491+
negative or 0.
492+
"""
493+
return HigherOrderFormulaBuilder(self, self._create_method).production()
494+
369495
async def _run(self) -> None:
370496
await self._builder.subscribe()
371497
steps, metric_fetchers = self._builder.finalize()

0 commit comments

Comments
 (0)