Skip to content

fix: preserve PV forecast on unexpected model load errors - #1162

Open
MMicieli wants to merge 6 commits into
davidusb-geek:masterfrom
MMicieli:fix/adjusted-pv-model-load-fallback-1144
Open

MMicieli wants to merge 6 commits into
davidusb-geek:masterfrom
MMicieli:fix/adjusted-pv-model-load-fallback-1144

Conversation

@MMicieli

@MMicieli MMicieli commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fixes #1144.

adjust_pv_forecast() is declared to return a pd.Series, and its existing handled failure paths preserve the original unadjusted PV forecast when the optional adjustment layer cannot be applied.

The generic cached-model load exception was the outlier: it returned boolean False, which then reached _prepare_dayahead_optim() and failed later at p_pv_forecast.values.

This PR keeps the adjusted-PV contract consistent by:

  • returning the original unadjusted p_pv_forecast on an unexpected cached-model load exception;
  • updating the existing generic-exception regression to assert the pd.Series fallback and verify prediction is not attempted;
  • documenting the handled fallback behaviour in the function return contract and Forecasts documentation.

Why this shape

This deliberately does not add caller-side boolean handling, a new return type, retry/state machinery, a configuration flag, or optimiser changes.

The base PV forecast is already valid at this point, and the surrounding adjusted-PV failure paths already fall back to it when the optional adjustment layer cannot be applied.

No configuration schema, default, API parameter, cookbook recipe, study case, optimiser, or Home Assistant production changes are required.

Reproducer

Before this change:

  1. Enable adjusted PV forecasting.
  2. Have a cached adjusted-PV model available for loading.
  3. Make model deserialisation raise an exception outside the explicitly handled pickle/import exception classes.
  4. adjust_pv_forecast() returns False.
  5. Day-ahead preparation continues because it only rejects None.
  6. p_pv_forecast.values then raises AttributeError: 'bool' object has no attribute 'values'.

The existing generic-exception regression now verifies the corrected fallback contract.

Validation

Validated head:

d270bbc431d3f775384bbc2b9f5e5c20a24732cc

GitHub Actions on that exact head:

  • Python test — PASS on Ubuntu
  • Python test — PASS on Windows
  • Python test — PASS on macOS
  • Code Quality Scan — PASS
  • Ruff — PASS
  • formatting check — PASS
  • CodeQL — PASS
  • Docker build/image test — PASS
  • CodeCov — PASS

Independent Windows validation also completed:

  • full test suite exercised;
  • Ruff passed;
  • formatting passed;
  • Sphinx HTML build succeeded.

The independent run initially exposed the pre-existing generic-exception test's old False assertion. Rather than adding a duplicate regression, this PR updates that existing test to the corrected pd.Series contract.

The Sphinx warnings observed during the independent build are pre-existing and outside the adjusted-PV documentation changed here.

Summary by Sourcery

Preserve a valid unadjusted PV forecast when adjusted-PV model loading fails unexpectedly.

Bug Fixes:

  • Preserve the original unadjusted PV forecast when an unexpected cached-model loading error prevents adjusted forecasting.

Enhancements:

  • Document the adjusted PV fallback contract and ensure the regression test verifies the fallback series, skipped prediction, and warning log.

Documentation:

  • Document that handled adjusted-PV model training and loading failures fall back to the unadjusted forecast.

Tests:

  • Update generic model-loading exception coverage to assert the unadjusted forecast fallback and that prediction is not attempted.

@sourcery-ai

sourcery-ai Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor
Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

The PR fixes an adjusted-PV failure path that returned False after an unexpected cached-model load error, causing a later Series access failure. It now returns the original unadjusted PV forecast, documents the contract, and updates the existing regression test to verify the fallback, logging, and absence of prediction.

Flow diagram for adjusted PV forecast fallback

flowchart TD
    A[adjust_pv_forecast] --> B{Cached model load}
    B -->|Success| C[adjust_pv_forecast_predict]
    B -->|Unexpected exception| D[Return original p_pv_forecast]
    D --> E[_prepare_dayahead_optim]
    E --> F[p_pv_forecast.values]
    C --> E
Loading

File-Level Changes

Change Details Files
Preserve the base PV forecast when cached adjusted-PV model loading fails unexpectedly.
  • Return the original forecast Series instead of boolean False.
  • Log an explicit warning describing the fallback.
  • Keep the existing downstream Series-based forecast contract unchanged.
src/emhass/command_line.py
Document the fallback behavior for handled adjusted-PV failures.
  • Clarify the function return contract.
  • Describe fallback behavior in Forecasts documentation.
src/emhass/command_line.py
docs/forecasts.md
Update regression coverage to enforce the corrected fallback contract.
  • Assert the returned Series is the original input.
  • Verify adjusted prediction is not attempted.
  • Check the unexpected-load error and fallback warning are logged.
tests/test_command_line_utils.py

Assessment against linked issues

Issue Objective Addressed Explanation
#1144 Ensure adjust_pv_forecast() does not return the invalid boolean False when adjusted PV model loading fails unexpectedly, instead preserving the valid unadjusted PV forecast or another consistently handled failure value. ✅
#1144 Prevent downstream day-ahead optimization from receiving an invalid value that causes an AttributeError when accessing p_pv_forecast.values. ✅
#1144 Add regression coverage and documentation for the corrected fallback behavior and return contract. ✅

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey - I've reviewed your changes and they look great!

Sourcery assessment

Approved.


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

adjust_pv_forecast() returns False on model-loading error, causing AttributeError downstream

1 participant