Repository: sktime/sktime
Pull request #7043 (2024-08-27 11:33:19)

[BUG] fix html display for `TransformedTargetForecaster` and `ForecastingPipeline`
The html display for `TransformedTargetForecaster` is failing since #6930, if estimators are passed as a list instead of list of tuples.

This is fixed by using the attribute that always returns a list of tuples. A test is also added.


Patch:
diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml
index 4ba72c742..3429b2ca5 100644
--- a/.github/workflows/wheels.yml
+++ b/.github/workflows/wheels.yml
@@ -27,76 +27,10 @@ jobs:
           name: wheels
           path: wheelhouse/*
 
-  test_unix_wheels:
-    needs: build_wheels
-    name: Test wheels on ${{ matrix.os }} with ${{ matrix.python-version }}
-    runs-on: ${{ matrix.os }}
-    strategy:
-      fail-fast: false  # to not fail all combinations if just one fail
-      matrix:
-        os: [ubuntu-latest, macos-13]
-        python-version: ['3.9', '3.10', '3.11', '3.12']
-
-    steps:
-      - uses: actions/checkout@v4
-      - uses: actions/setup-python@v5
-        with:
-          python-version: ${{ matrix.python-version }}
-
-      - uses: actions/download-artifact@v4
-        with:
-          name: wheels
-          path: wheelhouse
-
-      - name: Display downloaded artifacts
-        run: ls -l wheelhouse
-
-      - name: Get wheel filename
-        run: echo "WHEELNAME=$(ls ./wheelhouse/sktime-*none-any.whl)" >> $GITHUB_ENV
-
-      - name: Install wheel and extras
-        run: python -m pip install "${{ env.WHEELNAME }}[all_extras_pandas2,dev]"
-
-      - name: Run tests
-        run: make test_without_datasets
-
-  test_windows_wheels:
-    needs: build_wheels
-    name: Test wheels on ${{ matrix.os }} with ${{ matrix.python-version }}
-    runs-on: windows-latest
-    strategy:
-      fail-fast: false  # to not fail all combinations if just one fail
-      matrix:
-        os: [windows-latest]
-        python-version: ['3.9', '3.10', '3.11', '3.12']
-
-    steps:
-      - uses: actions/checkout@v4
-      - uses: actions/setup-python@v5
-        with:
-          python-version: ${{ matrix.python-version }}
-
-      - uses: actions/download-artifact@v4
-        with:
-          name: wheels
-          path: wheelhouse
-
-      - name: Display downloaded artifacts
-        run: ls -l wheelhouse
-
-      - name: Get wheel filename
-        run: echo "WHEELNAME=$(ls ./wheelhouse/sktime-*none-any.whl)" >> $env:GITHUB_ENV
-
-      - name: Install wheel and extras
-        run: python -m pip install "${env:WHEELNAME}[all_extras_pandas2,dev]"
-
-      - name: Run tests  # explicit commands as windows does not support make
-        run: python -m pytest  --ignore sktime/datasets
-
   upload_wheels:
     name: Upload wheels to PyPI
     runs-on: ubuntu-latest
-    needs: [build_wheels,test_unix_wheels,test_windows_wheels]
+    needs: [build_wheels]
 
     steps:
       - uses: actions/download-artifact@v4
diff --git a/sktime/forecasting/compose/_pipeline.py b/sktime/forecasting/compose/_pipeline.py
index bd80f57c0..4c59d5d27 100644
--- a/sktime/forecasting/compose/_pipeline.py
+++ b/sktime/forecasting/compose/_pipeline.py
@@ -280,15 +280,8 @@ class _Pipeline(_HeterogenousMetaEstimator, BaseForecaster):
         return [params1, params2, params3]
 
     def _sk_visual_block_(self):
-        _, estimators = zip(*self.steps)
+        names, estimators = zip(*self._steps)
 
-        def _get_name(name, est):
-            if est is None or est == "passthrough":
-                return f"{name}: passthrough"
-            # Is an estimator
-            return f"{name}: {est.__class__.__name__}"
-
-        names = [_get_name(name, est) for name, est in self.steps]
         name_details = [str(est) for est in estimators]
         return _VisualBlock(
             "serial",


Test patch:
diff --git a/sktime/forecasting/compose/tests/test_pipeline.py b/sktime/forecasting/compose/tests/test_pipeline.py
index 09b9c39b6..d9db79eb8 100644
--- a/sktime/forecasting/compose/tests/test_pipeline.py
+++ b/sktime/forecasting/compose/tests/test_pipeline.py
@@ -604,3 +604,21 @@ def test_pipeline_featurizer_noexog():
     # if the pipeline skips the FourierFeatures step,
     # then the predictions would be all constant, we test that this is not the case
     assert not np.allclose(y_pred.diff()[1:], np.zeros_like(y_pred[1:]))
+
+
+@pytest.mark.skipif(
+    not run_test_for_class(
+        [ForecastingPipeline, TransformedTargetForecaster, YfromX, Detrender],
+    ),
+    reason="run test only if softdeps are present and incrementally (if requested)",
+)
+def test_pipeline_display():
+    """Test that pipeline displays correctly."""
+    from sktime.forecasting.compose import TransformedTargetForecaster, YfromX
+    from sktime.transformations.series.detrend import Detrender
+
+    f = TransformedTargetForecaster([Detrender(), YfromX.create_test_instance()])
+    f._sk_visual_block_()
+
+    f = ForecastingPipeline([Detrender(), YfromX.create_test_instance()])
+    f._sk_visual_block_()