Skip to content

Fix TypeError when timesteps list has a gap in blending.steps.forecast#560

Open
Yuxiang-Ren-HUB wants to merge 1 commit into
pySTEPS:masterfrom
Yuxiang-Ren-HUB:fix-empty-subtimesteps-nonetype
Open

Fix TypeError when timesteps list has a gap in blending.steps.forecast#560
Yuxiang-Ren-HUB wants to merge 1 commit into
pySTEPS:masterfrom
Yuxiang-Ren-HUB:fix-empty-subtimesteps-nonetype

Conversation

@Yuxiang-Ren-HUB

Copy link
Copy Markdown

Problem

Calling pysteps.blending.steps.forecast() with a sparse timesteps list that has a gap (e.g. [1, 3], skipping 2) raises:

TypeError: 'NoneType' object is not iterable

at self.__state.final_blended_forecast[j].extend(...) inside __blended_nowcast_main_loop.

Root cause

In StepsBlendingNowcaster.__blended_nowcast_main_loop, worker(j) builds final_blended_forecast_single_member inside for t_sub in self.__state.subtimesteps:, but the line that stores it into final_blended_forecast_all_members_one_timestep[j] is indented one level too deep — inside that same for loop instead of after it:

for t_sub in self.__state.subtimesteps:
    if t_sub > 0:
        ...
        final_blended_forecast_single_member = (
            self.__post_process_output(...)
        )

    final_blended_forecast_all_members_one_timestep[j] = (   # <- inside the for loop
        final_blended_forecast_single_member
    )

When a requested timesteps list has a gap, nowcast_utils.binned_timesteps produces an empty bin for the skipped native step, so self.__state.subtimesteps == [] at that outer step. The for t_sub in []: loop body then never runs, so the assignment never happens, and final_blended_forecast_all_members_one_timestep[j] is left at its initial value of None. That later gets passed to .extend(None).

Note the two existing list-timesteps cases in test_blending_steps.py don't actually exercise this: [1, 2, 3] has no gap, and the other [1, 3] case uses zero_radar=True, zero_nwp=True, which takes an early-exit shortcut that skips the main loop entirely.

Fix

Dedent the assignment one level so it runs once per ensemble member after the subtimesteps loop finishes, regardless of whether that loop ran zero, one, or more iterations — matching the intent of "whatever this member produced at this outer step, even if that's nothing."

Testing

  • Added a regression test: timesteps=[1, 3] with non-zero radar/NWP precipitation (the two existing conditions needed to hit this bug at once).
  • Reproduced the crash directly against the pre-fix code, confirmed the fix resolves it with no other behavior change.
  • Full pysteps/tests/test_blending_steps.py suite: 59 passed (58 existing + 1 new).
  • black --check passes with no formatting changes needed.

final_blended_forecast_all_members_one_timestep[j] was assigned inside
the `for t_sub in subtimesteps:` loop, so when subtimesteps is empty
(a bin with no requested output, e.g. the skipped step 2 in
timesteps=[1, 3]) the assignment never ran and the value stayed at its
initial None. That later hit
`self.__state.final_blended_forecast[j].extend(None)`, raising
"TypeError: 'NoneType' object is not iterable".

Dedent the assignment one level so it runs once per member after the
subtimesteps loop completes, whether or not that loop ran at all.

Added a regression test (timesteps=[1, 3] with non-zero radar/NWP
precip) -- the two existing list-timesteps test cases didn't actually
exercise this path: [1, 2, 3] has no gap, and the other [1, 3] case
uses zero precipitation, which takes an early-exit shortcut that skips
the main loop entirely.
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.

1 participant