Skip to content

Commit 47d5366

Browse files
Mamba413claudehappy-otter
committed
fix: sklearn 1.6 compatibility - add __sklearn_tags__ and fix error msg
scikit-learn 1.6 removed _more_tags/_get_tags in favor of __sklearn_tags__. Any estimator that defines _more_tags without __sklearn_tags__ raises TypeError in check_estimator(). Add __sklearn_tags__ to all 9 affected classes while keeping _more_tags for backward compatibility. Also fix utilities.py error message format to match sklearn 1.6's check_n_features_in_after_fitting regex: "X has N features, but ClassName is expecting M features as input" Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
1 parent 798e887 commit 47d5366

3 files changed

Lines changed: 52 additions & 2 deletions

File tree

python/abess/decomposition.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,11 @@ def __init__(self, support_size=None, group=None,
135135
def _more_tags(self):
136136
return {'requires_y': False}
137137

138+
def __sklearn_tags__(self):
139+
tags = super().__sklearn_tags__()
140+
tags.requires_y = False
141+
return tags
142+
138143
def transform(self, X):
139144
r"""
140145
For PCA model, apply dimensionality reduction
@@ -574,6 +579,11 @@ def _more_tags(self):
574579
# (It just returns the transformation of `X`.)
575580
return {'_skip_test': True}
576581

582+
def __sklearn_tags__(self):
583+
tags = super().__sklearn_tags__()
584+
tags._skip_test = True
585+
return tags
586+
577587
def fit(self, X, y=None, r=None, sparse_matrix=False):
578588
r"""
579589
The fit function is used to transfer the information of

python/abess/linear.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,12 @@ def _more_tags(self):
9494
return {'binary_only': True,
9595
'no_validation': True}
9696

97+
def __sklearn_tags__(self):
98+
tags = super().__sklearn_tags__()
99+
tags.classifier_tags.multi_class = False
100+
tags.no_validation = True
101+
return tags
102+
97103
def predict_proba(self, X):
98104
r"""
99105
Give the probabilities of new sample
@@ -254,6 +260,10 @@ def __init__(self, path_type="seq", support_size=None,
254260
def _more_tags(self):
255261
return {'multioutput': False}
256262

263+
def __sklearn_tags__(self):
264+
tags = super().__sklearn_tags__()
265+
return tags
266+
257267
def predict(self, X):
258268
r"""
259269
Predict on given data.
@@ -384,6 +394,11 @@ def _more_tags(self):
384394
# 2-column `y` should be given (one for time, another for censoring).
385395
return {'_skip_test': True}
386396

397+
def __sklearn_tags__(self):
398+
tags = super().__sklearn_tags__()
399+
tags._skip_test = True
400+
return tags
401+
387402
def predict(self, X):
388403
r"""
389404
Returns the time-independent part of hazard function,
@@ -540,6 +555,11 @@ def __init__(self, path_type="seq", support_size=None,
540555
def _more_tags(self):
541556
return {"poor_score": True}
542557

558+
def __sklearn_tags__(self):
559+
tags = super().__sklearn_tags__()
560+
tags.regressor_tags.poor_score = True
561+
return tags
562+
543563
def predict(self, X):
544564
r"""
545565
Predict on given data.
@@ -688,6 +708,12 @@ def _more_tags(self):
688708
return {'multioutput': True,
689709
'multioutput_only': True}
690710

711+
def __sklearn_tags__(self):
712+
tags = super().__sklearn_tags__()
713+
tags.target_tags.multi_output = True
714+
tags.target_tags.single_output = False
715+
return tags
716+
691717
def predict(self, X):
692718
r"""
693719
Prediction of the mean of each response on given data.
@@ -825,6 +851,12 @@ def _more_tags(self):
825851
'no_validation': True,
826852
'poor_score': True}
827853

854+
def __sklearn_tags__(self):
855+
tags = super().__sklearn_tags__()
856+
tags.no_validation = True
857+
tags.classifier_tags.poor_score = True
858+
return tags
859+
828860
def predict_proba(self, X):
829861
r"""
830862
Give the probabilities of new data being assigned to different classes.
@@ -996,6 +1028,12 @@ def _more_tags(self):
9961028
return {'poor_score': True,
9971029
'requires_positive_y': True}
9981030

1031+
def __sklearn_tags__(self):
1032+
tags = super().__sklearn_tags__()
1033+
tags.regressor_tags.poor_score = True
1034+
tags.target_tags.required_positive = True
1035+
return tags
1036+
9991037
def predict(self, X):
10001038
r"""
10011039
Predict on given data.

python/abess/utilities.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,10 @@ def new_data_check(self, X, y=None, weights=None):
3939
# Check2 : X validation
4040
X = check_array(X, accept_sparse=True)
4141
if X.shape[1] != self.n_features_in_:
42-
raise ValueError("X.shape[1] should be " +
43-
str(self.n_features_in_))
42+
raise ValueError(
43+
f"X has {X.shape[1]} features, but {type(self).__name__} "
44+
f"is expecting {self.n_features_in_} features as input"
45+
)
4446

4547
# Check3 : X, y validation
4648
if (y is not None) and (weights is None):

0 commit comments

Comments
 (0)