Skip to content
3 changes: 2 additions & 1 deletion RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@

## Upgrading

<!-- Here goes notes on how to upgrade from previous versions, including deprecations and what they should be replaced with -->
* Update delivery period time filter validation to remove inappropriate start time check.

## New Features

* Add check to validate order details.
* CLI: Support delivery time filter in gridpool streams.

## Bug Fixes

Expand Down
8 changes: 6 additions & 2 deletions src/frequenz/client/electricity_trading/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,8 +300,10 @@ def gridpool_orders_stream(

Raises:
grpc.RpcError: If an error occurs while streaming the orders.
ValueError: If an invalid delivery_time_filter is provided.
"""
self.validate_params(delivery_time_filter=delivery_time_filter)
if delivery_time_filter and not delivery_time_filter.is_valid:
raise ValueError("Invalid delivery_time_filter provided.")

Copilot AI Jan 12, 2026

Copy link

Choose a reason for hiding this comment

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

The error message "Invalid delivery_time_filter provided." is not very informative about what makes the filter invalid. Consider providing a more descriptive error message that explains the validation failure, such as "Invalid delivery_time_filter: end time must be after start time" to help users understand and fix the issue.

Suggested change
raise ValueError("Invalid delivery_time_filter provided.")
raise ValueError(
"Invalid delivery_time_filter provided: ensure the start time is "
"before the end time and that all required fields are set."
)

Copilot uses AI. Check for mistakes.

gridpool_order_filter = GridpoolOrderFilter(
order_states=order_states,
Expand Down Expand Up @@ -366,8 +368,10 @@ def gridpool_trades_stream(

Raises:
grpc.RpcError: If an error occurs while streaming gridpool trades.
ValueError: If an invalid delivery_time_filter is provided.
"""
self.validate_params(delivery_time_filter=delivery_time_filter)
if delivery_time_filter and not delivery_time_filter.is_valid:
raise ValueError("Invalid delivery_time_filter provided.")

Copilot AI Jan 12, 2026

Copy link

Choose a reason for hiding this comment

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

The error message "Invalid delivery_time_filter provided." is not very informative about what makes the filter invalid. Consider providing a more descriptive error message that explains the validation failure, such as "Invalid delivery_time_filter: end time must be after start time" to help users understand and fix the issue.

Suggested change
raise ValueError("Invalid delivery_time_filter provided.")
raise ValueError(
"Invalid delivery_time_filter: please ensure that the start time "
"is before the end time and that all required fields are set."
)

Copilot uses AI. Check for mistakes.

gridpool_trade_filter = GridpoolTradeFilter(
trade_states=trade_states,
Expand Down
19 changes: 19 additions & 0 deletions src/frequenz/client/electricity_trading/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -1577,6 +1577,25 @@ def to_pb(self) -> electricity_trading_pb2.DeliveryTimeFilter:
),
)

@property
def is_valid(self) -> bool:
"""Check if the DeliveryTimeFilter is valid.

Verifies that the start and end dates in the time interval are logical, if both are set.

Returns:
True if the filter is valid, False otherwise.
"""
if self.time_interval is None:
return True

start = self.time_interval.start_time
end = self.time_interval.end_time
if start is None or end is None:
return True

return start < end


@dataclass(frozen=True)
class GridpoolOrderFilter:
Expand Down
64 changes: 46 additions & 18 deletions src/frequenz/client/electricity_trading/cli/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,15 @@ def cli() -> None:
@click.option("--url", required=True, type=str)
@click.option("--auth_key", required=True, type=str)
@click.option("--delivery-start", default=None, type=iso)
@click.option("--start", default=None, type=iso)
@click.option("--end", default=None, type=iso)
@click.option("--execution-from", default=None, type=iso)
@click.option("--execution-to", default=None, type=iso)
@click.option("--sign_secret", default=None, type=str)
def receive_public_trades( # pylint: disable=too-many-arguments
url: str,
auth_key: str,
*,
start: datetime,
end: datetime,
execution_from: datetime,
execution_to: datetime,
delivery_start: datetime,
sign_secret: str | None = None,
) -> None:
Expand All @@ -69,8 +69,8 @@ def receive_public_trades( # pylint: disable=too-many-arguments
url=url,
auth_key=auth_key,
delivery_start=delivery_start,
start=start,
end=end,
start=execution_from,
end=execution_to,
sign_secret=sign_secret,
)
)
Expand All @@ -80,15 +80,15 @@ def receive_public_trades( # pylint: disable=too-many-arguments
@click.option("--url", required=True, type=str)
@click.option("--auth_key", required=True, type=str)
@click.option("--delivery-start", default=None, type=iso)
@click.option("--start", default=None, type=iso)
@click.option("--end", default=None, type=iso)
@click.option("--execution-from", default=None, type=iso)
@click.option("--execution-to", default=None, type=iso)
@click.option("--sign_secret", default=None, type=str)
def receive_public_orders( # pylint: disable=too-many-arguments
url: str,
auth_key: str,
*,
start: datetime,
end: datetime,
execution_from: datetime,
execution_to: datetime,
delivery_start: datetime,
sign_secret: str | None = None,
) -> None:
Expand All @@ -98,25 +98,38 @@ def receive_public_orders( # pylint: disable=too-many-arguments
url=url,
auth_key=auth_key,
delivery_start=delivery_start,
start=start,
end=end,
start=execution_from,
end=execution_to,
sign_secret=sign_secret,
)
)


# pylint: disable=too-many-arguments
@cli.command()
@click.option("--url", required=True, type=str)
@click.option("--auth_key", required=True, type=str)
@click.option("--gid", required=True, type=int)
@click.option("--start", default=None, type=iso)
@click.option(
"--delivery-from",
default=None,
type=iso,
help="Start timestamp (inclusive) to filter delivery start times.",
)
@click.option(
"--delivery-to",
default=None,
type=iso,
help="End timestamp (exclusive) to filter delivery start times.",
)
@click.option("--sign_secret", default=None, type=str)
def receive_gridpool_trades(
url: str,
auth_key: str,
gid: int,
*,
start: datetime,
delivery_from: datetime | None,
delivery_to: datetime | None,
sign_secret: str | None = None,
) -> None:
"""List and/or stream gridpool trades."""
Expand All @@ -125,23 +138,37 @@ def receive_gridpool_trades(
url=url,
auth_key=auth_key,
gid=gid,
delivery_start=start,
delivery_from=delivery_from,
delivery_to=delivery_to,
sign_secret=sign_secret,
)
)


# pylint: disable=too-many-arguments
@cli.command()
@click.option("--url", required=True, type=str)
@click.option("--auth_key", required=True, type=str)
@click.option("--start", default=None, type=iso)
@click.option(
"--delivery-from",
default=None,
type=iso,
help="Start timestamp (inclusive) to filter delivery start times.",
)
@click.option(
"--delivery-to",
default=None,
type=iso,
help="End timestamp (exclusive) to filter delivery start times.",
)
@click.option("--gid", required=True, type=int)
@click.option("--sign_secret", default=None, type=str)
def receive_gridpool_orders(
url: str,
auth_key: str,
*,
start: datetime,
delivery_from: datetime | None,
delivery_to: datetime | None,
gid: int,
sign_secret: str | None = None,
) -> None:
Expand All @@ -150,7 +177,8 @@ def receive_gridpool_orders(
run_list_gridpool_orders(
url=url,
auth_key=auth_key,
delivery_start=start,
delivery_from=delivery_from,
delivery_to=delivery_to,
gid=gid,
sign_secret=sign_secret,
)
Expand Down
Loading