Skip to content

feat/3037 phase 1 refactor return types#3131

Open
ozink-u8 wants to merge 32 commits into
unit8co:masterfrom
ozink-u8:feat/3037-refactor-returnTypes-phase1
Open

feat/3037 phase 1 refactor return types#3131
ozink-u8 wants to merge 32 commits into
unit8co:masterfrom
ozink-u8:feat/3037-refactor-returnTypes-phase1

Conversation

@ozink-u8

@ozink-u8 ozink-u8 commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Checklist before merging this PR:

  • Mentioned all issues that this PR fixes or addresses.
  • Summarized the updates of this PR under Summary.
  • Added an entry under Unreleased in the Changelog.

Acts as a preparation for #3037.

Summary

Problem:
Many functions accepting TimeSeriesLike manually handle the single-vs-sequence type handling. The canonical example (a few sites vary slightly) is:

# Pattern A — hand-rolled shape dispatch (before)
called_with_single_series = isinstance(series, TimeSeries)
series = series2seq(series) # normalize to a sequence
result = [process(ts) for ts in series]
return result[0] if called_with_single_series else result

Change:
Replace that scattered logic with a single centralized exit through series2seq(...):

# Pattern B — centralized via series2seq (after)
sequence_type_in = get_series_seq_type(series)   # capture input shape
series = series2seq(series)
result = [process(ts) for ts in series]
return series2seq(result, seq_type_out=sequence_type_in)   # restore to input shape

Funnelling all single-vs-sequence handling through series2seq not only creates a single source of truth, which also eases the planned TSS introducing changes (Phase 2).

Other Information

  • These changes should be behavior preserving
  • Added overloads in ts_utils.py for ty typechecking.

Out of Scope

  • Several sites are intentionally deferred to Phase 2, for different reasons:
    • anomaly_model.py::score, returns a list[tuple[TS, ...]] for each scorer.
    • invertible_data_transformer.py::inverse_transform deals with historical forecasts, therefore of type SEQ_SEQ and flattens and reconstructs them.
    • forecasting_model.py::historical_forecasts: SEQ_SEQ touchpoint with lpo=False
    • forecasting_model.py::residuals: Uses HFC therefore SEQ_SEQ touchpoint with lpo=False
    • conformal_models.py::residuals: Uses HFC
    • conformal_models.py::_calibrate_forecasts Uses residuals -> HFC
    • historical_forecasts/utils.py::_apply_inverse_data_transformers: Touches SEQ_SEQ with lpo=False. Right now in this case series2seq just leaves SEQ_SEQ unchanged.
    • historical_forecasts/utils.py:: _process_historical_forecast_for_backtest Uses HFC -> SEQ_SEQ
    • datasets.py Many different datasets have hardcoded list[TS] as return type -> Would change to TSS in Phase 2 (Electricity, UberTLC, ILINet, ExchangeRate, Traffic, Weather)
    • explainability/explainability_result.py::{get_explanation, get_feature_values, get_attention}: query_explainability_result is generic (also returns shap.Explanation/DataFrame), so wrap the multi-series list[TimeSeries] as TSS in the getters, not the helper.
    • model_selection.py::make_splitter: Returns tuple for train, test of list/SplitTimeSeriesSequence objects. Which violates our rule of outer list being different TSs -> Intentionally left out
    • base_data_transformer.py::{apply_component_mask, unapply_component_mask}: Mixed return types including np.ndarray -> Unclear if should be refactored in Phase 2
    • metrics/utils.py Uses Literals as return not TS -> not relevant for TSS changes
    • anomaly_model.py::eval_metric + ad/utils.py::eval_metric_from_binary_prediction: Pattern-A shape but return dict/float (no TS to wrap) -> out of scope, left unmarked.

@ozink-u8 ozink-u8 requested a review from dennisbader as a code owner June 4, 2026 15:03
@ozink-u8 ozink-u8 force-pushed the feat/3037-refactor-returnTypes-phase1 branch from 6fbdb01 to 141684c Compare June 4, 2026 15:27
@codecov

codecov Bot commented Jun 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.49%. Comparing base (b0ccd3a) to head (5426dc9).

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3131      +/-   ##
==========================================
- Coverage   96.55%   96.49%   -0.07%     
==========================================
  Files         160      160              
  Lines       17285    17294       +9     
==========================================
- Hits        16689    16687       -2     
- Misses        596      607      +11     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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