Skip to content

Commit

Permalink
Unpin mkdocs-autorefs and fix multple URLs for warnings (#1051)
Browse files Browse the repository at this point in the history
This PR unpins the `mkdocs-autorefs` plugin, so we can use the latest
version, but to do that we need to make some changes to the way we link
to sections in the docs.

The new version produces warnings when there are more than one possible
URL to resolve an "autoref" link, and since we have strict more enabled,
the docs fail to build if we have any warnings.

The simplest way to avoid the warning in some cases is just adding the
following options:

```
  show_root_heading: false
  show_root_toc_entry: false
```

This avoids anchors being created in the user guide, so it removes the
ambiguity of the link.

To remove some other warnings we add a new `autorefs` plugin option to
`resolve_closest`, which allows to resolve the reference to the "closest
URL". See the documentation for more information:
https://github.com/mkdocstrings/autorefs#non-unique-headings.

This PR was done following suggestions in:

* mkdocstrings/autorefs#52
  • Loading branch information
llucax committed Sep 2, 2024
2 parents fce6d31 + ded52da commit 840bd9a
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 116 deletions.
11 changes: 3 additions & 8 deletions docs/user-guide/formula-engine.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
# Formula Engine

::: frequenz.sdk.timeseries.formula_engine.FormulaEngine
options:
members: None
show_bases: false
show_root_full_path: false
show_source: false

::: frequenz.sdk.timeseries.formula_engine.FormulaEngine3Phase
::: frequenz.sdk.timeseries.formula_engine
options:
members: None
show_bases: false
show_root_full_path: false
show_root_heading: false
show_root_toc_entry: false
show_source: false
2 changes: 2 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ markdown_extensions:
permalink: "¤"

plugins:
- autorefs:
resolve_closest: true
- gen-files:
scripts:
- docs/_scripts/mkdocstrings_autoapi.py
Expand Down
1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ dev-mkdocs = [
"black == 24.8.0",
"Markdown==3.7",
"mike == 2.1.3",
"mkdocs-autorefs >= 1.0.1, < 1.1",
"mkdocs-gen-files == 0.5.0",
"mkdocs-literate-nav == 0.6.1",
"mkdocs-macros-plugin == 1.0.5",
Expand Down
112 changes: 107 additions & 5 deletions src/frequenz/sdk/timeseries/formula_engine/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,114 @@
# License: MIT
# Copyright © 2023 Frequenz Energy-as-a-Service GmbH

"""The formula engine module.
"""Provides a way for the SDK to apply formulas on resampled data streams.
This module exposes the
[FormulaEngine][frequenz.sdk.timeseries.formula_engine.FormulaEngine] and
[FormulaEngine3Phase][frequenz.sdk.timeseries.formula_engine.FormulaEngine3Phase]
classes.
# Formula Engine
[`FormulaEngine`][frequenz.sdk.timeseries.formula_engine.FormulaEngine]s are used in the
SDK to calculate and stream metrics like
[`grid_power`][frequenz.sdk.timeseries.grid.Grid.power],
[`consumer_power`][frequenz.sdk.timeseries.consumer.Consumer.power], etc., which are
building blocks of the [Frequenz SDK Microgrid
Model][frequenz.sdk.microgrid--frequenz-sdk-microgrid-model].
The SDK creates the formulas by analysing the configuration of components in the
{{glossary("Component Graph")}}.
## Streaming Interface
The
[`FormulaEngine.new_receiver()`][frequenz.sdk.timeseries.formula_engine.FormulaEngine.new_receiver]
method can be used to create a [Receiver][frequenz.channels.Receiver] that streams the
[Sample][frequenz.sdk.timeseries.Sample]s calculated by the formula engine.
```python
from frequenz.sdk import microgrid
battery_pool = microgrid.new_battery_pool(priority=5)
async for power in battery_pool.power.new_receiver():
print(f"{power=}")
```
## Composition
Composite `FormulaEngine`s can be built using arithmetic operations on
`FormulaEngine`s streaming the same type of data.
For example, if you're interested in a particular composite metric that can be
calculated by subtracting
[`new_battery_pool().power`][frequenz.sdk.timeseries.battery_pool.BatteryPool.power] and
[`new_ev_charger_pool().power`][frequenz.sdk.timeseries.ev_charger_pool.EVChargerPool]
from the
[`grid().power`][frequenz.sdk.timeseries.grid.Grid.power],
we can build a `FormulaEngine` that provides a stream of this calculated metric as
follows:
```python
from frequenz.sdk import microgrid
battery_pool = microgrid.new_battery_pool(priority=5)
ev_charger_pool = microgrid.new_ev_charger_pool(priority=5)
grid = microgrid.grid()
# apply operations on formula engines to create a formula engine that would
# apply these operations on the corresponding data streams.
net_power = (
grid.power - (battery_pool.power + ev_charger_pool.power)
).build("net_power")
async for power in net_power.new_receiver():
print(f"{power=}")
```
# Formula Engine 3-Phase
A [`FormulaEngine3Phase`][frequenz.sdk.timeseries.formula_engine.FormulaEngine3Phase]
is similar to a
[`FormulaEngine`][frequenz.sdk.timeseries.formula_engine.FormulaEngine], except that
they stream [3-phase samples][frequenz.sdk.timeseries.Sample3Phase]. All the
current formulas (like
[`Grid.current_per_phase`][frequenz.sdk.timeseries.grid.Grid.current_per_phase],
[`EVChargerPool.current_per_phase`][frequenz.sdk.timeseries.ev_charger_pool.EVChargerPool.current_per_phase],
etc.) are implemented as per-phase formulas.
## Streaming Interface
The
[`FormulaEngine3Phase.new_receiver()`][frequenz.sdk.timeseries.formula_engine.FormulaEngine3Phase.new_receiver]
method can be used to create a [Receiver][frequenz.channels.Receiver] that streams the
[Sample3Phase][frequenz.sdk.timeseries.Sample3Phase] values
calculated by the formula engine.
```python
from frequenz.sdk import microgrid
ev_charger_pool = microgrid.new_ev_charger_pool(priority=5)
async for sample in ev_charger_pool.current_per_phase.new_receiver():
print(f"Current: {sample}")
```
## Composition
`FormulaEngine3Phase` instances can be composed together, just like `FormulaEngine`
instances.
```python
from frequenz.sdk import microgrid
ev_charger_pool = microgrid.new_ev_charger_pool(priority=5)
grid = microgrid.grid()
# Calculate grid consumption current that's not used by the EV chargers
other_current = (grid.current_per_phase - ev_charger_pool.current_per_phase).build(
"other_current"
)
async for sample in other_current.new_receiver():
print(f"Other current: {sample}")
```
"""

from ._formula_engine import FormulaEngine, FormulaEngine3Phase
Expand Down
158 changes: 56 additions & 102 deletions src/frequenz/sdk/timeseries/formula_engine/_formula_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,68 +57,39 @@


class FormulaEngine(Generic[QuantityT]):
"""[`FormulaEngine`][frequenz.sdk.timeseries.formula_engine.FormulaEngine]s are a
part of the SDK's data pipeline, and provide a way for the SDK to apply formulas on
resampled data streams.
"""An engine to apply formulas on resampled data streams.
They are used in the SDK to calculate and stream metrics like
[`grid_power`][frequenz.sdk.timeseries.grid.Grid.power],
[`consumer_power`][frequenz.sdk.timeseries.consumer.Consumer.power],
etc., which are building blocks of the
[Frequenz SDK Microgrid Model][frequenz.sdk.microgrid--frequenz-sdk-microgrid-model].
Please refer to the [module documentation][frequenz.sdk.timeseries.formula_engine]
for more information on how formula engines are used throughout the SDK.
The SDK creates the formulas by analysing the configuration of components in the
{{glossary("Component Graph")}}.
### Streaming Interface
The
[`FormulaEngine.new_receiver()`][frequenz.sdk.timeseries.formula_engine.FormulaEngine.new_receiver]
method can be used to create a
[Receiver](https://frequenz-floss.github.io/frequenz-channels-python/latest/reference/frequenz/channels/#frequenz.channels.Receiver)
that streams the [Sample][frequenz.sdk.timeseries.Sample]s calculated by the formula
engine.
```python
from frequenz.sdk import microgrid
battery_pool = microgrid.new_battery_pool(priority=5)
async for power in battery_pool.power.new_receiver():
print(f"{power=}")
```
### Composition
Example: Streaming the power of a battery pool.
```python
from frequenz.sdk import microgrid
Composite `FormulaEngine`s can be built using arithmetic operations on
`FormulaEngine`s streaming the same type of data.
battery_pool = microgrid.new_battery_pool(priority=5)
For example, if you're interested in a particular composite metric that can be
calculated by subtracting
[`new_battery_pool().power`][frequenz.sdk.timeseries.battery_pool.BatteryPool.power] and
[`new_ev_charger_pool().power`][frequenz.sdk.timeseries.ev_charger_pool.EVChargerPool]
from the
[`grid().power`][frequenz.sdk.timeseries.grid.Grid.power],
we can build a `FormulaEngine` that provides a stream of this calculated metric as
follows:
async for power in battery_pool.power.new_receiver():
print(f"{power=}")
```
```python
from frequenz.sdk import microgrid
Example: Composition of formula engines.
```python
from frequenz.sdk import microgrid
battery_pool = microgrid.new_battery_pool(priority=5)
ev_charger_pool = microgrid.new_ev_charger_pool(priority=5)
grid = microgrid.grid()
battery_pool = microgrid.new_battery_pool(priority=5)
ev_charger_pool = microgrid.new_ev_charger_pool(priority=5)
grid = microgrid.grid()
# apply operations on formula engines to create a formula engine that would
# apply these operations on the corresponding data streams.
net_power = (
grid.power - (battery_pool.power + ev_charger_pool.power)
).build("net_power")
# apply operations on formula engines to create a formula engine that would
# apply these operations on the corresponding data streams.
net_power = (
grid.power - (battery_pool.power + ev_charger_pool.power)
).build("net_power")
async for power in net_power.new_receiver():
print(f"{power=}")
```
""" # noqa: D400, D205
async for power in net_power.new_receiver():
print(f"{power=}")
```
"""

def __init__(
self,
Expand Down Expand Up @@ -392,54 +363,37 @@ def new_receiver(


class FormulaEngine3Phase(Generic[QuantityT]):
"""A
[`FormulaEngine3Phase`][frequenz.sdk.timeseries.formula_engine.FormulaEngine3Phase]
is similar to a
[`FormulaEngine`][frequenz.sdk.timeseries.formula_engine.FormulaEngine], except that
they stream [3-phase samples][frequenz.sdk.timeseries.Sample3Phase]. All the
current formulas (like
[`Grid.current_per_phase`][frequenz.sdk.timeseries.grid.Grid.current_per_phase],
[`EVChargerPool.current_per_phase`][frequenz.sdk.timeseries.ev_charger_pool.EVChargerPool.current_per_phase],
etc.) are implemented as per-phase formulas.
### Streaming Interface
The
[`FormulaEngine3Phase.new_receiver()`][frequenz.sdk.timeseries.formula_engine.FormulaEngine3Phase.new_receiver]
method can be used to create a
[Receiver](https://frequenz-floss.github.io/frequenz-channels-python/latest/reference/frequenz/channels/#frequenz.channels.Receiver)
that streams the [Sample3Phase][frequenz.sdk.timeseries.Sample3Phase] values
calculated by the formula engine.
```python
from frequenz.sdk import microgrid
ev_charger_pool = microgrid.new_ev_charger_pool(priority=5)
async for sample in ev_charger_pool.current_per_phase.new_receiver():
print(f"Current: {sample}")
```
### Composition
`FormulaEngine3Phase` instances can be composed together, just like `FormulaEngine`
instances.
```python
from frequenz.sdk import microgrid
ev_charger_pool = microgrid.new_ev_charger_pool(priority=5)
grid = microgrid.grid()
# Calculate grid consumption current that's not used by the EV chargers
other_current = (grid.current_per_phase - ev_charger_pool.current_per_phase).build(
"other_current"
)
async for sample in other_current.new_receiver():
print(f"Other current: {sample}")
```
""" # noqa: D205, D400
"""An engine to apply formulas on 3-phase resampled data streams.
Please refer to the [module documentation][frequenz.sdk.timeseries.formula_engine]
for more information on how formula engines are used throughout the SDK.
Example: Streaming the current of an EV charger pool.
```python
from frequenz.sdk import microgrid
ev_charger_pool = microgrid.new_ev_charger_pool(priority=5)
async for sample in ev_charger_pool.current_per_phase.new_receiver():
print(f"Current: {sample}")
```
Example: Composition of formula engines.
```python
from frequenz.sdk import microgrid
ev_charger_pool = microgrid.new_ev_charger_pool(priority=5)
grid = microgrid.grid()
# Calculate grid consumption current that's not used by the EV chargers
other_current = (grid.current_per_phase - ev_charger_pool.current_per_phase).build(
"other_current"
)
async for sample in other_current.new_receiver():
print(f"Other current: {sample}")
```
"""

def __init__(
self,
Expand Down

0 comments on commit 840bd9a

Please sign in to comment.