-
-
Notifications
You must be signed in to change notification settings - Fork 26k
[MRG] DOC Instructions for changing default value of a certain parameter #11469
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
[MRG] DOC Instructions for changing default value of a certain parameter #11469
Conversation
Thanks @qinhanmin2014 ! I was also not certain about the recommended way. From #11043 (comment),
Would you remember where this was discussed? I looked into some of the linked issues: most appear to have used either None or something else instead of "deprecated", but I probably missed something :) |
@rth Here is the comment from @jnothman |
Got it, thanks. What about From https://docs.python.org/3.7/library/warnings.html#warning-categories
Hmm, this does suggest to use FeatureWarning for parameter renaming if I read this correctly? |
Also from the above description, I'm not sure if scikit-learn users belong to "other Python developers" or "end users of applications that are written in Python" category. |
(1) I had to admit that I used to distinguish these two warnings through their names (which happens to be similar to what's recommended before python 3.7), so thanks for the materials. |
(also ping @lesteve who commented about this in linked issues) |
I have to say I am not sure there is a generic way of doing this so this is a bit tricky to document. For example IMO:
I even seem to remember that there have been PRs where we combined both (in a first step FutureWarning to warn that the default value is going to change, with a promise that once the default value changes to add a DeprecationWarning on the old default value when set explicitly). IMO this one is a bit too conservative. Here is what I would propose:
Maybe it would be good to list a few recent PRs (sorry if this has been done already somewhere) that did change the default value so we can have a closer look about what our general approach is "in the wild". |
Thanks all for the instant reply. It's hard to figure our a good way but I think we should figure out an acceptable way and provide it to contributors ASAP. |
doc/developers/contributing.rst
Outdated
@@ -796,11 +796,28 @@ In the following example, k is deprecated and renamed to n_clusters:: | |||
"will be removed in 0.15.", DeprecationWarning) | |||
n_clusters = k | |||
|
|||
If the default value of a parameter needs to be changed, it is recommended to |
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 would something else than recommended if we actually impose it :)
I would go with this approach but I am fine with anything chosen. I don't think that this is actually a blocker until that we agree on how do it.
The PR LGTM apart of the above comment which I think could be addressed in the narrative as well. |
I think we have used deprecation warnings for changing defaults in the past but maybe FutureWarning is better in this case. |
doc/developers/contributing.rst
Outdated
raise ``FutureWarning`` when users are using the default value. In the | ||
following example, we change the default value of ``n_clusters`` from 5 to 10 | ||
(current version is 0.20). You can also refer to recent merged PRs | ||
(e.g., `#10331 <https://github.com/scikit-learn/scikit-learn/pull/10331>`__ |
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.
they will not be recent for long. maybe remove these and instead say everything important here?
doc/developers/contributing.rst
Outdated
warnings.warn("The default value of n_clusters will change from " | ||
"5 to 10 in 0.22.", FutureWarning) | ||
n_clusters = 5 | ||
|
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 there should also be an example for an __init__
parameter in a class to show that the deprecation needs to happen in ``fit..
Thanks all for the instant reply. I agree that it's hard to figure out a perfect solution, but I think we should provide an acceptable solution to users ASAP. |
Thanks @glemaitre for the great improvements :) These changes LGTM from my side. |
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
doc/developers/contributing.rst
Outdated
def example_function(n_clusters=8, k=None): | ||
if k is not None: | ||
def example_function(n_clusters=8, k='deprecated'): | ||
if k != 'deprecated': |
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.
Speaking with @lesteve, it is true that this line look really weird in english:
"if k is not deprecated then warn for deprecation"
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.
@glemaitre @lesteve
I think deprecated
, along with warn
can be regarded as symbols here. k != 'deprecated'
can be regarded as : if you use the deprecated parameter, then we 'll raise DeprecationWarning.
Revert back to None
if you don't like 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 warn
makes sense for changed behaviors, because then it's
if value == "warn":
# do the warning
as below. we could have "not specified" for removing a parameter as a symbol.
if value != "not specified":
# do the warning
That's less clear in the signature, though.
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.
maybe "not used" would be better?
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.
These are great instructions!
Two things are missing, though:
A deprecation requires a test that the warning is raised in the relevant cases and not in the other cases, AND the deprecation warning should be caught in all other tests, and there should be no warning in the examples. Maybe that removes a note box or some other emphasis?
doc/developers/contributing.rst
Outdated
warnings.warn("'k' was renamed to n_clusters in version 0.13 and " | ||
"will be removed in 0.15.", DeprecationWarning) | ||
n_clusters = k | ||
|
||
When the change is in a class, we conduct validate and raise warning in ``fit``:: |
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.
either "we validate" or "we conduct validation" thought I'd prefer the first.
doc/developers/contributing.rst
Outdated
|
||
import warnings | ||
|
||
class ExampleEstimator: |
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.
inherit from BaseEstimator maybe? I mean not necessary but why not?
doc/developers/contributing.rst
Outdated
def example_function(n_clusters=8, k=None): | ||
if k is not None: | ||
def example_function(n_clusters=8, k='deprecated'): | ||
if k != 'deprecated': |
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.
maybe "not used" would be better?
doc/developers/contributing.rst
Outdated
``FutureWarning`` when users are using the default value. In the following | ||
example, we change the default value of ``n_clusters`` from 5 to 10 | ||
(current version is 0.20). You can also refer to merged PRs | ||
(e.g., `#10331 <https://github.com/scikit-learn/scikit-learn/pull/10331>`__ |
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.
do these add anything? I mean I'm not super opposed but I'm not sure what's in the PR that's not 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.
I would remove the PR references. I imagine the discussion is a bit chaotic compared to the guidelines we are trying to provide.
this makes me so happy :) |
@amueller Thanks :) comments addressed.
Originally, I intend to show users how to do the deprecation in a function through an example, and show users how to do the deprecation in a class through merged PRs. Now, we have an example for a class, so they don't add anything. But I think it's still useful to tell users to refer to merged PRs.
I agree and add it. But I suggest that you check my comment #11043 (comment). Currently, we fail to do so. |
Yes, I know, we're in a very bad state right now wrt deprecation warnings :-/ One more reason to emphasize that. |
@@ -790,17 +790,66 @@ In the following example, k is deprecated and renamed to n_clusters:: | |||
|
|||
import warnings | |||
|
|||
def example_function(n_clusters=8, k=None): | |||
if k is not None: | |||
def example_function(n_clusters=8, k='not_used'): |
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 |
sorry for nagging again, but maybe it would be even better to say how to catch the deprecation warnings. Because I'm not actually sure what's the right way to do that and to test that the right warnings are raised ;) |
I see that it could be useful but more for user than for contributor, isn't it. In this section we try to explain how to raise it while the catching of the warning should be in another section accessible to all user, IMO. |
As discussed in person: no, if you make a deprecation you should make sure all the warnings you expect are caught and there are no warnings left. |
Basically, it seems that |
Actually it does not matter. When we want to assert warnings/no warnings, we actually do not want to filter them. |
I think at the moment there are two ways to ignore warnings |
The caveat is that sometimes you can not use |
Thanks. Since we have two subsections now, I also summarize the TODOs in the new section.
I'm going to follow @lesteve & @glemaitre and recommend |
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.
Small typo otherwise LGTM. Thanks @qinhanmin2014! This will be very useful.
doc/developers/contributing.rst
Outdated
|
||
Similar to deprecations, the warning message should always give both the | ||
version in which the change happened and the version in which the old behavior | ||
will be removed. The docstring needs to updated accordingly. We need a test |
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.
to be updated
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 @albertcthomas :) Corrected.
Merging since that we have 4 reviewers who approved this PR |
will be removed. The docstring needs to be updated accordingly. We need a test | ||
which ensures that the warning is raised in relevant cases but not in other | ||
cases. The warning should be caught in all other tests | ||
(using e.g., ``pytest.mark.filter_warnings``), and there should be no warning |
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.
@glemaitre Should we use @pytest.mark.filterwarnings
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.
+1
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.
@aboucaud I've pushed to master, please refer the latest doc :)
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 but you forgot to remove the _
:)
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.
Oops, thanks a lot @aboucaud :)
You can decorate the function with it. It was what we saw with @lesteve
yesterday.
…On 16 July 2018 at 17:16, Hanmin Qin ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In doc/developers/contributing.rst
<#11469 (comment)>
:
> + class ExampleEstimator:
+ def __init__(self, n_clusters='warn'):
+ self.n_clusters = n_clusters
+
+ def fit(self, X, y):
+ if self.n_clusters == 'warn':
+ warnings.warn("The default value of n_clusters will change from "
+ "5 to 10 in 0.22.", FutureWarning)
+ self._n_clusters = 5
+
+Similar to deprecations, the warning message should always give both the
+version in which the change happened and the version in which the old behavior
+will be removed. The docstring needs to be updated accordingly. We need a test
+which ensures that the warning is raised in relevant cases but not in other
+cases. The warning should be caught in all other tests
+(using e.g., ``pytest.mark.filter_warnings``), and there should be no warning
@glemaitre <https://github.com/glemaitre> Should we use
@pytest.mark.filterwarnings here?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#11469 (review)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AHG9P7K1ysvnp5zA6jlUlqr4llS1cEKrks5uHK5jgaJpZM4VJjWW>
.
--
Guillaume Lemaitre
INRIA Saclay - Parietal team
Center for Data Science Paris-Saclay
https://glemaitre.github.io/
|
I've not reviewed this, @qinhanmin2014, but I'm really glad we have this
resource!!
|
Closes #11219 Closes #11283
We have several PRs (marked as blocker) which aim to change the default value of a certain parameter, but seems that contributors don't know our way of doing these things.
Currently, I only write down our consensus (I think). Whether we should take care of tests/examples when changing the default value of a parameter is still unclear.
See #11043 (comment)
cc @jnothman