|
1 | 1 | # Frequenz Python SDK Release Notes
|
2 | 2 |
|
3 |
| -## Summary |
4 |
| - |
5 |
| -This release replaces the `@actor` decorator with a new `Actor` class. |
6 |
| - |
7 |
| -## Upgrading |
8 |
| - |
9 |
| - |
10 |
| -- The `frequenz.sdk.power` package contained the power distribution algorithm, which is for internal use in the sdk, and is no longer part of the public API. |
11 |
| - |
12 |
| -- `PowerDistributingActor`'s result type `OutOfBound` has been renamed to `OutOfBounds`, and its member variable `bound` has been renamed to `bounds`. |
13 |
| - |
14 |
| -- The `@actor` decorator was replaced by the new `Actor` class. The main differences between the new class and the old decorator are: |
15 |
| - |
16 |
| - * It doesn't start automatically, `start()` needs to be called to start an actor (using the `frequenz.sdk.actor.run()` function is recommended). |
17 |
| - * The method to implement the main logic was renamed from `run()` to `_run()`, as it is not intended to be run externally. |
18 |
| - * Actors can have an optional `name` (useful for debugging/logging purposes). |
19 |
| - * The actor will only be restarted if an unhandled `Exception` is raised by `_run()`. It will not be restarted if the `_run()` method finishes normally. If an unhandled `BaseException` is raised instead, it will be re-raised. For normal cancellation the `_run()` method should handle `asyncio.CancelledError` if the cancellation shouldn't be propagated (this is the same as with the decorator). |
20 |
| - * The `_stop()` method is public (`stop()`) and will `cancel()` and `await` for the task to finish, catching the `asyncio.CancelledError`. |
21 |
| - * The `join()` method is renamed to `wait()`, but they can also be awaited directly ( `await actor`). |
22 |
| - * For deterministic cleanup, actors can now be used as `async` context managers. |
23 |
| - |
24 |
| - Most actors can be migrated following these steps: |
25 |
| - |
26 |
| - 1. Remove the decorator |
27 |
| - 2. Add `Actor` as a base class |
28 |
| - 3. Rename `run()` to `_run()` |
29 |
| - 4. Forward the `name` argument (optional but recommended) |
30 |
| - |
31 |
| - For example, this old actor: |
32 |
| - |
33 |
| - ```python |
34 |
| - from frequenz.sdk.actor import actor |
35 |
| - |
36 |
| - @actor |
37 |
| - class TheActor: |
38 |
| - def __init__(self, actor_args) -> None: |
39 |
| - # init code |
40 |
| - |
41 |
| - def run(self) -> None: |
42 |
| - # run code |
43 |
| - ``` |
44 |
| - |
45 |
| - Can be migrated as: |
46 |
| - |
47 |
| - ```python |
48 |
| - import asyncio |
49 |
| - from frequenz.sdk.actor import Actor |
50 |
| - |
51 |
| - class TheActor(Actor): |
52 |
| - def __init__(self, actor_args, |
53 |
| - *, |
54 |
| - name: str | None = None, |
55 |
| - ) -> None: |
56 |
| - super().__init__(name=name) |
57 |
| - # init code |
58 |
| - |
59 |
| - def _run(self) -> None: |
60 |
| - # run code |
61 |
| - ``` |
62 |
| - |
63 |
| - Then you can instantiate all your actors first and then run them using: |
64 |
| - |
65 |
| - ```python |
66 |
| - from frequenz.sdk.actor import run |
67 |
| - # Init code |
68 |
| - actor = TheActor() |
69 |
| - other_actor = OtherActor() |
70 |
| - # more setup |
71 |
| - await run(actor, other_actor) # Start and await for all the actors |
72 |
| - ``` |
73 |
| - |
74 |
| -- The `MovingWindow` is now a `BackgroundService`, so it needs to be started manually with `window.start()`. It is recommended to use it as an `async` context manager if possible though: |
75 |
| - |
76 |
| - ```python |
77 |
| - async with MovingWindow(...) as window: |
78 |
| - # The moving windows is started here |
79 |
| - use(window) |
80 |
| - # The moving window is stopped here |
81 |
| - ``` |
82 |
| - |
83 |
| -- The base actors (`ConfigManagingActor`, `ComponentMetricsResamplingActor`, `DataSourcingActor`, `PowerDistributingActor`) now inherit from the new `Actor` class, if you are using them directly, you need to start them manually with `actor.start()` and you might need to do some other adjustments. |
84 |
| - |
85 |
| -- The `BatteryPool.power_distribution_results` method has been enhanced to provide power distribution results in the form of `Power` objects, replacing the previous use of `float` values. |
86 |
| - |
87 |
| -- In the `Request` class: |
88 |
| - * The attribute `request_timeout_sec` has been updated and is now named `request_timeout` and it is represented by a `timedelta` object rather than a `float`. |
89 |
| - * The attribute `power` is now presented as a `Power` object, as opposed to a `float`. |
90 |
| - |
91 |
| -- Within the `EVChargerPool.set_bounds` method, the parameter `max_amps` has been redefined as `max_current`, and it is now represented using a `Current` object instead of a `float`. |
92 |
| - |
93 |
| -- The argument `nones_are_zeros` in `FormulaEngine` and related classes and methods is now a keyword-only argument. |
94 |
| - |
95 |
| -## New Features |
96 |
| - |
97 |
| -- Added `DFS` to the component graph |
98 |
| - |
99 |
| -- `BackgroundService`: This new abstract base class can be used to write other classes that runs one or more tasks in the background. It provides a consistent API to start and stop these services and also takes care of the handling of the background tasks. It can also work as an `async` context manager, giving the service a deterministic lifetime and guaranteed cleanup. |
100 |
| - |
101 |
| - All classes spawning tasks that are expected to run for an indeterminate amount of time are likely good candidates to use this as a base class. |
102 |
| - |
103 |
| -- `Actor`: This new class inherits from `BackgroundService` and it replaces the `@actor` decorator. |
104 |
| - |
105 |
| -- Newly added `min` and `max` functions for Formulas. They can be used as follows: |
106 |
| - |
107 |
| - ```python |
108 |
| - formula1.min(formula2) |
109 |
| - ``` |
110 |
| - |
111 | 3 | ## Bug Fixes
|
112 | 4 |
|
113 |
| -- Fixes a bug in the ring buffer updating the end timestamp of gaps when they are outdated. |
114 |
| - |
115 |
| -- Properly handles PV configurations with no or only some meters before the PV component. |
116 |
| - |
117 |
| - So far we only had configurations like this: `Meter -> Inverter -> PV`. However the scenario with `Inverter -> PV` is also possible and now handled correctly. |
118 |
| - |
119 |
| -- Fix `consumer_power()` not working certain configurations. |
120 |
| - |
121 |
| - In microgrids without consumers and no main meter, the formula would never return any values. |
122 |
| - |
123 |
| -- Fix `pv_power` not working in setups with 2 grid meters by using a new reliable function to search for components in the components graph |
124 |
| - |
125 |
| -- Fix `consumer_power` and `producer_power` similar to `pv_power` |
126 |
| - |
127 |
| -- Zero value requests received by the `PowerDistributingActor` will now always be accepted, even when there are non-zero exclusion bounds. |
128 |
| - |
129 |
| -- Hold on to a reference to all streaming tasks in the microgrid API client, so they don't get garbage collected. |
| 5 | +- Fix the **API Reference** link in the documentation website navigation bar. |
0 commit comments