Skip to content

Conversation

@shsms
Copy link
Contributor

@shsms shsms commented Nov 20, 2025

  • Also implements the new Formula/Formula3Phase classes to replace the old formula engine, for supporting the new formula functions - max/min/coalesce.
  • Drops the old component graph and the old formula engine

@shsms shsms requested a review from a team as a code owner November 20, 2025 22:44
@shsms shsms requested review from Copilot and daniel-zullo-frequenz and removed request for a team November 20, 2025 22:44
@github-actions github-actions bot added part:docs Affects the documentation part:tests Affects the unit, integration and performance (benchmarks) tests part:tooling Affects the development tooling (CI, deployment, dependency management, etc.) part:data-pipeline Affects the data pipeline part:core Affects the SDK core components (data structures, etc.) part:microgrid Affects the interactions with the microgrid labels Nov 20, 2025
@shsms
Copy link
Contributor Author

shsms commented Nov 20, 2025

Based on #1283

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR switches from a Python-based component graph and formula engine to a new Rust-based implementation, introducing new Formula and Formula3Phase classes to support advanced formula functions (max/min/coalesce) and removing deprecated code.

Key Changes:

  • Replaced old Python formula engine with new Rust-based component graph
  • Implemented new Formula and Formula3Phase classes with support for max/min/coalesce functions
  • Updated component data structures to use new client library types
  • Removed deprecated formula engine tests and implementation

Reviewed Changes

Copilot reviewed 109 out of 118 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/timeseries/test_formula_engine.py Entire file deleted - old formula engine tests removed
tests/timeseries/test_consumer.py Added missing resampler calls for battery and PV inverter power
tests/timeseries/mock_resampler.py Updated to use new Metric enum instead of ComponentMetricId
tests/timeseries/mock_microgrid.py Updated component types and connection structures to match new API
tests/timeseries/_formulas/test_lexer.py New test file for formula lexer functionality
tests/timeseries/_formulas/test_formulas_3_phase.py New test file for three-phase formula support
tests/timeseries/_formulas/test_formulas.py New comprehensive formula tests with max/min/coalesce support
tests/timeseries/_formulas/test_formula_composition.py Updated to use new formula API and async context managers
src/frequenz/sdk/timeseries/formulas/_token.py New token definitions for formula parsing
src/frequenz/sdk/timeseries/formulas/_resampled_stream_fetcher.py New component for fetching resampled telemetry streams
src/frequenz/sdk/timeseries/formulas/_peekable.py New peekable iterator implementation for parsing
src/frequenz/sdk/timeseries/formulas/_parser.py New formula parser implementation
src/frequenz/sdk/timeseries/formulas/_lexer.py New formula lexer implementation
src/frequenz/sdk/timeseries/formulas/_functions.py New function implementations (max/min/coalesce)
Comments suppressed due to low confidence (1)

tests/timeseries/mock_microgrid.py:9

  • The import Callable from collections.abc on line 10 is unused after the changes. The Callable type is imported again on line 12 from the typing module via the Coroutine import, and all usages in the file appear to use the typing module's Callable (e.g., line 260). This unused import should be removed.
from collections.abc import Callable

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@shsms shsms force-pushed the new-formulas+new-graph= branch from 4583c7d to c942e5f Compare November 20, 2025 22:49
@llucax
Copy link
Contributor

llucax commented Nov 21, 2025

Can you rebase it on top of Based on #1293 instead?

@shsms
Copy link
Contributor Author

shsms commented Nov 25, 2025

Can you rebase it on top of Based on #1293 instead?

#1293 is making changes to a lot of the files that are being deleted by this PR. I'd rather take this in first, then drop the changes on these files, then we only need to review required changes.

@shsms
Copy link
Contributor Author

shsms commented Nov 25, 2025

Oh, maybe those changes are from the api PR. don't know. Let's take the API PR first then, we can decide.

@shsms shsms force-pushed the new-formulas+new-graph= branch 2 times, most recently from 706118b to cc1e61b Compare November 26, 2025 17:19
@shsms
Copy link
Contributor Author

shsms commented Nov 26, 2025

It was actually trivial to rebase on top of #1293. Done.

@shsms shsms force-pushed the new-formulas+new-graph= branch from cc1e61b to 09b029b Compare November 26, 2025 17:29
@shsms
Copy link
Contributor Author

shsms commented Nov 26, 2025

Damn, this causes my tests to fail. Switched back to based on #1283.

@shsms shsms force-pushed the new-formulas+new-graph= branch 3 times, most recently from c88d813 to 4f25d12 Compare November 28, 2025 13:56
@llucax
Copy link
Contributor

llucax commented Dec 4, 2025

This needs a rebase now.

shsms added 3 commits December 4, 2025 13:29
Signed-off-by: Sahas Subramanian <sahas.subramanian@proton.me>
Signed-off-by: Sahas Subramanian <sahas.subramanian@proton.me>
Signed-off-by: Sahas Subramanian <sahas.subramanian@proton.me>
shsms added 3 commits December 4, 2025 13:29
Signed-off-by: Sahas Subramanian <sahas.subramanian@proton.me>
Signed-off-by: Sahas Subramanian <sahas.subramanian@proton.me>
Signed-off-by: Sahas Subramanian <sahas.subramanian@proton.me>
@shsms shsms force-pushed the new-formulas+new-graph= branch from 4f25d12 to 2470c10 Compare December 4, 2025 12:29
Signed-off-by: Sahas Subramanian <sahas.subramanian@proton.me>
@shsms
Copy link
Contributor Author

shsms commented Dec 4, 2025

Rebased

@llucax
Copy link
Contributor

llucax commented Dec 10, 2025

FYI: I started reviewing 👀

Copy link
Contributor

@llucax llucax left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, yeah, 45 comments 😬

Of course most of it are minor and some are just about the same issue.

To summarize:

  • Missing docstrings, I would add them to this PR, as it should be very low effort and important.

  • __format__(), I would create an issue about it if you think it is a good idea, not necessary at all for this PR.

  • TelemetryStream using float: Same, only discuss if it makes sense and if it does can be a separate issue.

  • @dataclass with kw_only, I would do it for this PR, as it should also be low effort, but not very important so also fine to create an issue.

  • Function.from_string() vs parse_function: Also curious to discuss, but OK to leave as it is.

  • Peekable: I think support for None should be fixed in this PR, not sure if by using peekable from more-itertools or fix ours. I have mixed feelings, pulling a dependency for such a small thing seems overkill, but then this lib has a lot of other useful stuff, so maybe having it as a dependency maybe is not bad. Similar to asyncstdlib, at some point maybe it is good to have it in the toolbox by default.

  • Docstring rendering fixes should probably be applied in this PR too

  • with pytest.raises(StopIteration) also probably good to change in this PR, as it is low effort

  • Adding error case to lexer, and having more tests in general (is it me or the new stuff is a bit undertested? Or is it tested indirectly?) could be done as separate issue/PR.

  • Rename components -> stream can be done in this PR if you agree, but optional

  • About using TaskGroup, I would push for it. According to Python docs of gather():

    Note

    A new alternative to create and run tasks concurrently and wait for their completion is asyncio.TaskGroup. TaskGroup provides stronger safety guarantees than gather for scheduling a nesting of subtasks: if a task (or a subtask, a task scheduled by a task) raises an exception, TaskGroup will, while gather will not, cancel the remaining scheduled tasks).

  • Overriding cancel() + await() instead of stop() is important, but if things work for now can also be done in a separate issue/PR.

  • Use of pytest.mark.parametrize also of course optional, but I would do it (even if in a separate PR/issue), AI should do it well in a few seconds and error reporting will be better when things fail.

  • Formala3Phase, also fine to leave as it is in this PR, but I think we need to take the opportunity in this refactoring to get it right ASAP.

  • NON_EXISTING_COMPONENT_ID same, I would love to see it go, probably not in this PR, but I would like to use this refactoring impulse to get rid of it ASAP.

  • Making somehow formulas more generic to take a metrici + quantity: definitely not for this PR, but I would like to discuss

  • Move _graph_traversal, probably for this PR

  • Having a ComponentGraph that inherits (and specializes) from the new rust component graph: I would definitely do it. I know many advantages are now pointless because you updated the code already, but still, I think it makes things much easier than this long type hints and the mix of methods and free functions we have in this PR.

  • I would also remove the is_xxx() wrappers over isinstance() in this PR unless there is a very good reason to have them.

  • Remove types-networkx in this PR.

  • Why 2 inverters now? would be nice to know and document better

  • And also try to keep the deprecated aliases FormulaEngine and FormulaEngine3Phase, if not in this PR add them later, but before the release so hopefully we can make it a non-breaking change.

There are a few other small comments and questions that are completely optional.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If FormulaEngine and FormulaEngine3Phase were part of the public interface, and you say the interface didn't really changed (so the class were only renamed), can we keep a deprecated alias with the old names so we can make this a non-breaking change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any ideas how?

With newer python, we could do type FormulaEngine[W] = Formula[W].

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or I can just rename the thing back to FormulaEngine. Just thought it was weird because technically we can call everything an engine, resampling engine, etc.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess with TypeAlias, not sure if it works with generics too, but also not sure if deprecated works with it, so probably the easiest approach would be to use inheritance:

@deprecated("...")
class FormulaEngine(Formula[T]): pass

Then you should be able to pass a FormulaEngine to every place a Formula is expected and get the deprecation message both in the interpreter and type checkers.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can actually rename the whole thing back to FormulaEngine. It was convenient to have two names during development, but FormulaEngine makes it more easily identifiable, different from the abstract concept of a formula.

@shsms
Copy link
Contributor Author

shsms commented Dec 12, 2025

This is ready again @llucax .

And so is #1322

Copy link
Contributor

@llucax llucax left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the backwards compatibility thing is really important, but we can do anytime before the release.

@github-project-automation github-project-automation bot moved this from To do to Review approved in Python SDK Roadmap Dec 15, 2025
@shsms shsms added this pull request to the merge queue Dec 15, 2025
Merged via the queue into frequenz-floss:v1.x.x with commit c953071 Dec 15, 2025
5 checks passed
@shsms shsms deleted the new-formulas+new-graph=🎉 branch December 15, 2025 10:36
@github-project-automation github-project-automation bot moved this from Review approved to Done in Python SDK Roadmap Dec 15, 2025
@llucax llucax added this to the v1.0.0-rc2300 milestone Dec 16, 2025
github-merge-queue bot pushed a commit that referenced this pull request Dec 16, 2025
These changes were introduced in the PRs #1295 and #1322, and are being
reverted here.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

part:core Affects the SDK core components (data structures, etc.) part:data-pipeline Affects the data pipeline part:docs Affects the documentation part:microgrid Affects the interactions with the microgrid part:tests Affects the unit, integration and performance (benchmarks) tests part:tooling Affects the development tooling (CI, deployment, dependency management, etc.)

Projects

Development

Successfully merging this pull request may close these issues.

3 participants