-
-
Notifications
You must be signed in to change notification settings - Fork 26.2k
FIX (SLEP6) descriptor shouldn't override method #32111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Co-authored-by: Omar Salman <[email protected]>
…into slep6/refactor
Co-authored-by: Stefanie Senger <[email protected]>
Co-authored-by: Stefanie Senger <[email protected]>
…learn into slep6/pipeline/score
Co-authored-by: Omar Salman <[email protected]>
Co-authored-by: Omar Salman <[email protected]>
# metadata with an UNUSED marker, and that the parent class has | ||
# the method already. In this case, we cannot remove the method | ||
# since it exists in the parent class, and instead we set it with | ||
# an empty set of requests. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aren't we simply not setting any RequestMethod for such cases instead of an empty set of requests?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The issue is "not setting a RequestMethod" means we inherit the one from the parent class, which in the case of LogisticRegressionCV
means having one accepting a sample_weight
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we need to set one but with empty requests?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, exactly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then shouldn't we be setting requests = dict() in this branch rather than simply continuing the loop?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This branch has not hasattr(cls, set_method_name)
, otherwise we don't come here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the comment is a bit misleading, since it talks about the reason to add the not hasattr(cls, set_method_name)
condition into the code compared to before rather than about the whole condition.
Co-authored-by: Omar Salman <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thank you @adrinjalali
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, @adrinjalali!
I have checked the rendered docs and built locally, but I don’t see that LogisticRegressionCV.set_score_request()
has a different docstring compared to before. Maybe I misunderstand the PR, but I cannot see how the def set_score_request()
in _BaseScorer
would be prevented from being overridden while a CV meta-estimator is defined, since there is no inheritance between those two.
And searching the repo, _BaseScorer is the only place that defines their own set_score_request
.
Is this PR rather for third party libraries?
I also suggested a few documentation improvements.
def is_RequestMethod(obj, name: str): | ||
value = inspect.getattr_static(obj, name) | ||
return isinstance(value, RequestMethod) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Structurally, is_RequestMethod
is a bit similar to defines_get_metadata_routing
from #31695. Both check whether an estimator defines something itself or inherits it and feel like workarounds for going through MROs.
For maintainability, do you think we could reduce some of these MRO iterations (for instance via class methods, as you mentioned once)?
try: | ||
for method in SIMPLE_METHODS: | ||
set_method_name = f"set_{method}_request" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
set_method_name
could be called set_method_request
as a more intuitive variable name.
# metadata with an UNUSED marker, and that the parent class has | ||
# the method already. In this case, we cannot remove the method | ||
# since it exists in the parent class, and instead we set it with | ||
# an empty set of requests. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the comment is a bit misleading, since it talks about the reason to add the not hasattr(cls, set_method_name)
condition into the code compared to before rather than about the whole condition.
# The method is not a descriptor, which means it's explicitly | ||
# defined in the class, therefore we skip overriding it with a | ||
# descriptor here. | ||
# This happens, for instance in Scorers where the | ||
# `set_score_request` method is defined in the class. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# The method is not a descriptor, which means it's explicitly | |
# defined in the class, therefore we skip overriding it with a | |
# descriptor here. | |
# This happens, for instance in Scorers where the | |
# `set_score_request` method is defined in the class. | |
# `set_method_name` is not a `RequestMethod` so we skip | |
# overriding it. For example, in Scorers the `set_score_request` | |
# method is explicitly defined in the class. |
Maybe a bit more straightforward?
@@ -1438,14 +1448,35 @@ def __init_subclass__(cls, **kwargs): | |||
---------- | |||
.. [1] https://www.python.org/dev/peps/pep-0487 | |||
""" | |||
|
|||
def is_RequestMethod(obj, name: str): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def is_RequestMethod(obj, name: str): | |
def _is_RequestMethod(obj, method_name: str): | |
# Check if a method is a descriptor. |
I think it would be a private method.
If a class implements a
set_{method}_request
explicitly (like done in scorers), then the descriptor shouldn't be overriding it.xref: #30859 (comment)
cc @antoinebaker @OmarManzoor
This fixes some existing issues. The added tests should represent where things were failing.