Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 6 additions & 12 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,9 @@

## Upgrading

* The following enums are now deprecated and will be removed in a future release:
* The `frequenz.client.common.microgrid.electrical_components.ElectricalComponentCategory` enum is now deprecated and will be removed in a future release.

* `frequenz.client.common.microgrid.electrical_components.ElectricalComponentCategory`
* `frequenz.client.common.microgrid.electrical_components.BatteryType`
* `frequenz.client.common.microgrid.electrical_components.InverterType`
* `frequenz.client.common.microgrid.electrical_components.EvChargerType`

Accessing any member of these enums will emit a `DeprecationWarning`. Users are encouraged to switch to the `ElectricalComponent` class hierarchy (using `match` expressions or `isinstance()`) to identify components.
Accessing any member of this enum will emit a `DeprecationWarning`. Users are encouraged to switch to the `ElectricalComponent` class hierarchy (using `match` expressions or `isinstance()`) to identify components.

Client implementers: To convert a component class to the protobuf enum values the server expects, use the new `electrical_component_class_to_proto()` / `electrical_component_class_from_proto()` converters (see New Features).

Expand All @@ -32,11 +27,7 @@
...
```

The related proto-layer converters (`electrical_component_category_to_proto`, `electrical_component_category_from_proto`, `battery_type_to_proto`, `battery_type_from_proto`, `inverter_type_to_proto`, `inverter_type_from_proto`, `ev_charger_type_to_proto`, `ev_charger_type_from_proto`) are also deprecated.

* The `category` attribute of `ElectricalComponent` and the `type` attribute of `Battery`, `Inverter`, and `EvCharger` are now deprecated properties. Accessing them emits a `DeprecationWarning`. They no longer appear in `repr()`.

Use `match` or `isinstance()` on the class hierarchy to identify components instead.
The related proto-layer converters (`electrical_component_category_to_proto`, `electrical_component_category_from_proto`) are also deprecated.

* The `UNSPECIFIED` members in the following enums are now deprecated:

Expand Down Expand Up @@ -88,6 +79,9 @@
* Added a new `frequenz.client.common.microgrid.Microgrid` type, together with the `frequenz.client.common.microgrid.proto.v1alpha8.microgrid_from_proto` conversion function.

* Added a new `frequenz.client.common.microgrid.electrical_components` package, featuring a `ElectricalComponent` class hierarchy and its families (battery, inverter, EV charger, etc.), and `ElectricalComponentConnection`, including `v1alpha8` proto conversion functions.

The class of a component is its identity; components don't carry category or type attributes. The only exceptions are the error-recovery classes `UnrecognizedElectricalComponent` and `MismatchedCategoryElectricalComponent` (with a raw protobuf `category` value) and `UnrecognizedBattery`, `UnrecognizedInverter` and `UnrecognizedEvCharger` (with a raw protobuf `type` value), which preserve the raw protobuf values received from the protocol version used to load them.

* Added a new `frequenz.client.common.microgrid.Microgrid` type with a raising `is_active()` method, together with the `frequenz.client.common.microgrid.proto.v1alpha8.microgrid_from_proto` conversion function.

## Bug Fixes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

from ._battery import (
Battery,
BatteryType,
BatteryTypes,
LiIonBattery,
NaIonBattery,
Expand All @@ -26,7 +25,6 @@
AcEvCharger,
DcEvCharger,
EvCharger,
EvChargerType,
EvChargerTypes,
HybridEvCharger,
UnrecognizedEvCharger,
Expand All @@ -39,7 +37,6 @@
BatteryInverter,
HybridInverter,
Inverter,
InverterType,
InverterTypes,
PvInverter,
UnrecognizedInverter,
Expand Down Expand Up @@ -71,7 +68,6 @@
"AcEvCharger",
"Battery",
"BatteryInverter",
"BatteryType",
"BatteryTypes",
"Breaker",
"CapacitorBank",
Expand All @@ -88,14 +84,12 @@
"ElectricalComponentTypes",
"Electrolyzer",
"EvCharger",
"EvChargerType",
"EvChargerTypes",
"GridConnectionPoint",
"Hvac",
"HybridEvCharger",
"HybridInverter",
"Inverter",
"InverterType",
"InverterTypes",
"LiIonBattery",
"Meter",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,171 +4,44 @@
"""Battery electrical component."""

import dataclasses
import warnings
from typing import Any, Self, TypeAlias

import typing_extensions
from frequenz.core.enum import Enum, deprecated_member, unique

from ._electrical_component import ElectricalComponent

_BATTERY_TYPE_DEPRECATION_MESSAGE = (
"BatteryType is deprecated; identify batteries via isinstance() on the "
"class hierarchy, or convert with "
"electrical_component_class_to_proto()/electrical_component_class_from_proto()."
)


def _battery_type_member_message(name: str) -> str:
"""Build the deprecation message for a specific `BatteryType` member.

Args:
name: The enum member name.

Returns:
The full deprecation message for that member.
"""
return (
f"BatteryType.{name} is deprecated; identify batteries via isinstance() "
"on the class hierarchy, or convert with "
"electrical_component_class_to_proto()/electrical_component_class_from_proto()."
)


@typing_extensions.deprecated(_BATTERY_TYPE_DEPRECATION_MESSAGE)
@unique
class BatteryType(Enum):
"""The known types of batteries."""

UNSPECIFIED = deprecated_member(0, _battery_type_member_message("UNSPECIFIED"))
"""The battery type is unspecified."""

LI_ION = deprecated_member(1, _battery_type_member_message("LI_ION"))
"""Lithium-ion (Li-ion) battery."""

NA_ION = deprecated_member(2, _battery_type_member_message("NA_ION"))
"""Sodium-ion (Na-ion) battery."""


@dataclasses.dataclass(frozen=True, kw_only=True)
class Battery(ElectricalComponent):
"""An abstract battery electrical component."""

_category: int = dataclasses.field(
default=5, repr=False
) # ElectricalComponentCategory.BATTERY
"""The category of this electrical component.

Note:
This should not be used normally, you should test if an electrical
component [`isinstance`][] of a concrete electrical component class
instead.

It is only provided for using with a newer version of the API where
the client doesn't know about a new category yet (i.e. for use with
[`UnrecognizedElectricalComponent`][...UnrecognizedElectricalComponent])
and in case some low level code needs to know the category of an electrical
component.
"""

_type: int = dataclasses.field(repr=False)
"""The type of this battery.

Note:
This should not be used normally, you should test if a battery
[`isinstance`][] of a concrete battery class instead.

It is only provided for using with a newer version of the API where
the client doesn't know about the new battery type yet (i.e. for use
with [`UnrecognizedBattery`][...UnrecognizedBattery]).
"""

# pylint: disable-next=unused-argument
def __new__(cls, *args: Any, **kwargs: Any) -> Self:
"""Prevent instantiation of this class."""
if cls is Battery:
raise TypeError(f"Cannot instantiate {cls.__name__} directly")
return super().__new__(cls)

@property
@typing_extensions.deprecated(
"BatteryType is deprecated; identify batteries via isinstance() on the "
"class hierarchy, or convert with "
"electrical_component_class_to_proto()/electrical_component_class_from_proto()."
)
def type(self) -> BatteryType | int:
"""The deprecated type of this battery."""
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
try:
return BatteryType(self._type)
except ValueError:
return self._type


@dataclasses.dataclass(frozen=True, kw_only=True)
class UnspecifiedBattery(Battery):
"""A battery of an unspecified type."""

_type: int = dataclasses.field(default=0, repr=False) # BatteryType.UNSPECIFIED
"""The type of this battery.

Note:
This should not be used normally, you should test if a battery
[`isinstance`][] of a concrete battery class instead.

It is only provided for using with a newer version of the API where
the client doesn't know about the new battery type yet (i.e. for use
with [`UnrecognizedBattery`][...UnrecognizedBattery]).
"""


@dataclasses.dataclass(frozen=True, kw_only=True)
class LiIonBattery(Battery):
"""A Li-ion battery."""

_type: int = dataclasses.field(default=1, repr=False) # BatteryType.LI_ION
"""The type of this battery.

Note:
This should not be used normally, you should test if a battery
[`isinstance`][] of a concrete battery class instead.

It is only provided for using with a newer version of the API where
the client doesn't know about the new battery type yet (i.e. for use
with [`UnrecognizedBattery`][...UnrecognizedBattery]).
"""


@dataclasses.dataclass(frozen=True, kw_only=True)
class NaIonBattery(Battery):
"""A Na-ion battery."""

_type: int = dataclasses.field(default=2, repr=False) # BatteryType.NA_ION
"""The type of this battery.

Note:
This should not be used normally, you should test if a battery
[`isinstance`][] of a concrete battery class instead.

It is only provided for using with a newer version of the API where
the client doesn't know about the new battery type yet (i.e. for use
with [`UnrecognizedBattery`][...UnrecognizedBattery]).
"""


@dataclasses.dataclass(frozen=True, kw_only=True)
class UnrecognizedBattery(Battery):
"""A battery of an unrecognized type."""

_type: int = dataclasses.field(repr=False)
"""The unrecognized type of this battery."""

@property
@typing_extensions.override
def type(self) -> int:
"""The deprecated type of this battery."""
return self._type
type: int
"""The raw type of this battery, not recognized by this library version."""


BatteryTypes: TypeAlias = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,3 @@
@dataclasses.dataclass(frozen=True, kw_only=True)
class Breaker(ElectricalComponent):
"""A breaker electrical component."""

_category: int = dataclasses.field(
default=7, repr=False
) # ElectricalComponentCategory.BREAKER
"""The category of this electrical component."""
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,3 @@
@dataclasses.dataclass(frozen=True, kw_only=True)
class CapacitorBank(ElectricalComponent):
"""A capacitor bank electrical component."""

_category: int = dataclasses.field(
default=17, repr=False
) # ElectricalComponentCategory.CAPACITOR_BANK
"""The category of this electrical component."""
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,3 @@
@dataclasses.dataclass(frozen=True, kw_only=True)
class Chp(ElectricalComponent):
"""A combined heat and power (CHP) electrical component."""

_category: int = dataclasses.field(
default=9, repr=False
) # ElectricalComponentCategory.CHP
"""The category of this electrical component."""
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,3 @@
@dataclasses.dataclass(frozen=True, kw_only=True)
class Converter(ElectricalComponent):
"""An AC-DC converter electrical component."""

_category: int = dataclasses.field(
default=4, repr=False
) # ElectricalComponentCategory.CONVERTER
"""The category of this electrical component."""
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,3 @@
@dataclasses.dataclass(frozen=True, kw_only=True)
class CryptoMiner(ElectricalComponent):
"""A crypto miner electrical component."""

_category: int = dataclasses.field(
default=14, repr=False
) # ElectricalComponentCategory.CRYPTO_MINER
"""The category of this electrical component."""
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,14 @@
"""Base electrical component from which all other electrical components inherit."""

import dataclasses
import warnings
from collections.abc import Mapping
from datetime import datetime, timezone
from typing import Any, Self

import typing_extensions

from ..._exception import UnspecifiedValueError
from ...metrics import Bounds, Metric
from ...types import Lifetime
from .. import MicrogridId
from ._category import ElectricalComponentCategory
from ._ids import ElectricalComponentId


Expand All @@ -29,19 +25,6 @@ class ElectricalComponent: # pylint: disable=too-many-instance-attributes
microgrid_id: MicrogridId
"""The ID of the microgrid this electrical component belongs to."""

_category: int = dataclasses.field(repr=False)
"""The category of this electrical component.

Note:
This should not be used normally, you should test if an electrical component
[`isinstance`][] of a concrete electrical component class instead.

It is only provided for using with a newer version of the API where the client
doesn't know about a new category yet (i.e. for use with
[`UnrecognizedElectricalComponent`][...UnrecognizedElectricalComponent]) and
in case some low level code needs to know the category of an electrical component.
"""

name: str | None = None
"""The name of this electrical component."""

Expand Down Expand Up @@ -119,21 +102,6 @@ def __post_init__(self) -> None:
"instances via the corresponding *_from_proto converter."
)

@property
@typing_extensions.deprecated(
"ElectricalComponentCategory is deprecated; identify components via "
"isinstance() on the class hierarchy, or convert with "
"electrical_component_class_to_proto()/electrical_component_class_from_proto()."
)
def category(self) -> ElectricalComponentCategory | int:
"""The deprecated category of this electrical component."""
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
try:
return ElectricalComponentCategory(self._category)
except ValueError:
return self._category

def provides_telemetry(self) -> bool:
"""Check whether this electrical component provides telemetry data.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,3 @@
@dataclasses.dataclass(frozen=True, kw_only=True)
class Electrolyzer(ElectricalComponent):
"""An electrolyzer electrical component."""

_category: int = dataclasses.field(
default=10, repr=False
) # ElectricalComponentCategory.ELECTROLYZER
"""The category of this electrical component."""
Loading
Loading