From 343d19bd46c3e17a74578513dfbda9eb21d5feb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dea=20Mar=C3=ADa=20L=C3=A9on?= Date: Fri, 4 Jul 2025 10:55:27 +0200 Subject: [PATCH 1/3] avoid empty Pipeline --- sklearn/pipeline.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sklearn/pipeline.py b/sklearn/pipeline.py index f46c150b40313..a06116f8734b0 100644 --- a/sklearn/pipeline.py +++ b/sklearn/pipeline.py @@ -246,6 +246,8 @@ class Pipeline(_BaseComposition): } def __init__(self, steps, *, transform_input=None, memory=None, verbose=False): + if not steps: + raise ValueError("Please add steps to Pipeline") self.steps = steps self.transform_input = transform_input self.memory = memory From 391e8f5b65346f2653a0fb476f6e3257751bfd6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dea=20Mar=C3=ADa=20L=C3=A9on?= Date: Tue, 8 Jul 2025 10:36:32 +0200 Subject: [PATCH 2/3] Avoid fitting a pipeline without steps --- sklearn/pipeline.py | 5 ++--- sklearn/tests/test_pipeline.py | 10 ++++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/sklearn/pipeline.py b/sklearn/pipeline.py index a06116f8734b0..f43e5a124671d 100644 --- a/sklearn/pipeline.py +++ b/sklearn/pipeline.py @@ -246,8 +246,6 @@ class Pipeline(_BaseComposition): } def __init__(self, steps, *, transform_input=None, memory=None, verbose=False): - if not steps: - raise ValueError("Please add steps to Pipeline") self.steps = steps self.transform_input = transform_input self.memory = memory @@ -322,6 +320,8 @@ def set_params(self, **kwargs): return self def _validate_steps(self): + if not self.steps: + raise ValueError("Please add steps to Pipeline") names, estimators = zip(*self.steps) # validate names @@ -1291,7 +1291,6 @@ def __sklearn_is_fitted__(self): An empty pipeline is considered fitted. """ - # First find the last step that is not 'passthrough' last_step = None for _, estimator in reversed(self.steps): diff --git a/sklearn/tests/test_pipeline.py b/sklearn/tests/test_pipeline.py index ad00ffb67a616..f3d9c803c5aae 100644 --- a/sklearn/tests/test_pipeline.py +++ b/sklearn/tests/test_pipeline.py @@ -282,6 +282,16 @@ def test_pipeline_invalid_parameters(): assert params == params2 +def test_empty_pipeline(): + X = iris.data + y = iris.target + + pipe = Pipeline([]) + msg = "Please add steps to Pipeline" + with pytest.raises(ValueError, match=msg): + pipe.fit(X, y) + + def test_pipeline_init_tuple(): # Pipeline accepts steps as tuple X = np.array([[1, 2]]) From 92bd2a660ac33ca64754d1646eca1dc41c1048f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dea=20Mar=C3=ADa=20L=C3=A9on?= Date: Tue, 8 Jul 2025 12:26:04 +0200 Subject: [PATCH 3/3] clearer message --- sklearn/pipeline.py | 2 +- sklearn/tests/test_pipeline.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sklearn/pipeline.py b/sklearn/pipeline.py index f43e5a124671d..95eb5df275468 100644 --- a/sklearn/pipeline.py +++ b/sklearn/pipeline.py @@ -321,7 +321,7 @@ def set_params(self, **kwargs): def _validate_steps(self): if not self.steps: - raise ValueError("Please add steps to Pipeline") + raise ValueError("The pipeline is empty. Please add steps.") names, estimators = zip(*self.steps) # validate names diff --git a/sklearn/tests/test_pipeline.py b/sklearn/tests/test_pipeline.py index f3d9c803c5aae..3815f264a8e7f 100644 --- a/sklearn/tests/test_pipeline.py +++ b/sklearn/tests/test_pipeline.py @@ -287,7 +287,7 @@ def test_empty_pipeline(): y = iris.target pipe = Pipeline([]) - msg = "Please add steps to Pipeline" + msg = "The pipeline is empty. Please add steps." with pytest.raises(ValueError, match=msg): pipe.fit(X, y)