8000 FIX available_if used on an unbound method (#20655) · rth/scikit-learn@cc8d84a · GitHub
[go: up one dir, main page]

Skip to content

Commit cc8d84a

Browse files
authored
FIX available_if used on an unbound method (scikit-learn#20655)
1 parent 4f33e4d commit cc8d84a

File tree

2 files changed

+22
-6
lines changed

2 files changed

+22
-6
lines changed

sklearn/utils/metaestimators.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -100,22 +100,27 @@ def __init__(self, fn, check, attribute_name):
100100
update_wrapper(self, fn)
101101

102102
def __get__(self, obj, owner=None):
103+
attr_err = AttributeError(
104+
f"This {repr(owner.__name__)} has no attribute {repr(self.attribute_name)}"
105+
)
103106
if obj is not None:
104107
# delegate only on instances, not the classes.
105108
# this is to allow access to the docstrings.
106109
if not self.check(obj):
107-
raise AttributeError(
108-
f"This {repr(owner.__name__)}"
109-
" has no attribute"
110-
f" {repr(self.attribute_name)}"
111-
)
110+
raise attr_err
112111

113112
# lambda, but not partial, allows help() to work with update_wrapper
114113
out = lambda *args, **kwargs: self.fn(obj, *args, **kwargs) # noqa
115114
else:
115+
116+
def fn(*args, **kwargs):
117+
if not self.check(args[0]):
118+
raise attr_err
119+
return self.fn(*args, **kwargs)
120+
116121
# This makes it possible to use the decorated method as an unbound method,
117122
# for instance when monkeypatching.
118-
out = lambda *args, **kwargs: self.fn(*args, **kwargs) # noqa
123+
out = lambda *args, **kwargs: fn(*args, **kwargs) # noqa
119124
# update the docstring of the returned function
120125
update_wrapper(out, self.fn)
121126
return out

sklearn/utils/tests/test_metaestimators.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import pytest
2+
13
from sklearn.utils.metaestimators import if_delegate_has_method
24
from sklearn.utils.metaestimators import available_if
35

@@ -105,9 +107,18 @@ def test_available_if():
105107
assert hasattr(AvailableParameterEstimator(), "available_func")
106108
assert not hasattr(AvailableParameterEstimator(available=False), "available_func")
107109

110+
111+
def test_available_if_unbound_method():
108112
# This is a non regression test for:
109113
# https://github.com/scikit-learn/scikit-learn/issues/20614
110114
# to make sure that decorated functions can be used as an unbound method,
111115
# for instance when monkeypatching.
112116
est = AvailableParameterEstimator()
113117
AvailableParameterEstimator.available_func(est)
118+
119+
est = AvailableParameterEstimator(available=False)
120+
with pytest.raises(
121+
AttributeError,
122+
match="This 'AvailableParameterEstimator' has no attribute 'available_func'",
123+
):
124+
AvailableParameterEstimator.available_func(est)

0 commit comments

Comments
 (0)
0