-
-
Notifications
You must be signed in to change notification settings - Fork 481
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
Deprecation for private and semi-private callables #38211
Comments
@mkoeppe @tscrim @kwankyu Pinging you three because of the discussion on my PR, also about deprecating things. Travis has commented in the past on my other PR that semi-private and private methods indeed do not go through the deprecation process, but other developers are saying I'm cherry-picking comments, so writing this down somewhere concrete would be better. |
To avoid further confusion, let's try to settle down this issue. Continuing the discussion from #38207, I suggest: The deprecation policy means what is described in https://doc.sagemath.org/html/en/developer/coding_in_python.html#deprecation. We want to clarify the policy with the following details: (S) Only the definitions of functions/methods/attributes/classes living under More suggestions? Missing cases? |
EDIT: Stroke my comment after the next two comments. |
I worry that (C) is too permissive. For example, Is there an example of a class that you think should be considered internal? |
indeed, (C) should not happen.
|
Right. Then do you think that If you think so, would you suggest a replacement of (C)? Or do you think any class name (starting with a letter other than an underscore) change should be subject to the deprecation policy? |
Yes, this is a good example for this discussion. The public API to create a number field is through the |
Does the deprecation policy apply only to renaming the class, or also to changing methods on it? I agree that it's probably fine to rename |
Users should certainly be able to rely on the interface of public methods of objects that have been constructed using public API. |
I'm not opposed to the proposal but just for the record, these classes are in
|
If we adopt (C), then this gives a clear reason to choose either one of Moreover after adopting (C), if one wants to make a public version out of |
We should regard these as exceptions to the rule (C) initially, and sort them our case by case basis with deprecation warnings. Thanks for the list. |
How about (C) A class that is not imported into the global namespace and whose name has an underscore anywhere is internal, and is not subject to the deprecation policy. This means that the name of the class can be changed, but methods on the class may still be subject to deprecation if instances of the class are returned by Sage's public API. |
If (C) applies to a class, the class is internal, and anything with it can be done without deprecation warning, including even removing the class entirely as we refactor code. As Matthias put it, public methods of the class accessible by public API should still be accessible via other class by public API. |
Regarding deprecation of things in the public namespace, see |
Another relevant pointer: https://doc.sagemath.org/html/en/developer/packaging_sage_library.html#module-level-runtime-dependencies on the "modularization anti-pattern" |
This one was recently garbage-collected |
Any class that is in our public documentation is subject to be imported and used in a user's code (such as my own that I have/will not make a PR for). So (C) or any variation thereof is a poor option as it is very likely to break code in the wild (without any deprecation message); especially as we are moving to doing I think (ME) is the only sensible thing to do. If a user is really using hidden functions, they clearly know what they are doing and understand the risks that it might change without notice. Experimental code explicitly says it can change without notice. |
We aren't moving to doing |
Sorry, I was not being precise enough. Yes, we are moving towards that and away from |
Of course these ABCs are in the public documentation. |
What does not check out is the other direction. Just because an implementation class is documented, it does not mean that it is part of the public API. |
I don't think I agree with this argument. A Is this what you had in mind? |
How are you defining documentation here? In a strict reading, whereby it is a method/function/etc. with a docstring, then yes. Yet, my point is about what is public, and to me, that is what appears in our reference manual as we say that is the official (public) SageMath documentation. That is what you typically find by Google, what I tell people to look at, etc.
If you want to hide it, then make it a
Does that clarify? Of course, we don't have to add a particular |
That's much too rigid. Our documentation is written for a wide audience, not just for an audience that is looking for stable public API. |
According to the documentation,
|
Any solution using |
Would subclassing work with imported lazy_import object? |
No, because a |
So still (RNC) will break the user code... This is better than no deprecation message. ? |
The primary purpose of deprecation is compatibility, not sending messages. It will again depend on common sense / domain expertise to determine whether compatibility for subclassing should be sacrificed just for issuing a deprecation message. |
For a removed (rather to be removd) public class, (RMC) would work? But this is a rare (if ever) case... |
Again no. Would not work for subclassing... |
The primary purpose is rather sending message while keeping compatibility. The intention is to notify the user with what would happen before it happens. "Incompatibility and message" seems better than "compatibility and no message". and I think (RNC) is a good solution for all other cases. |
Absolutely not. |
"compatibility and no message" is just a delayed break (with surprise) of user code. No? |
That's right. Delaying a breaking change is the point of deprecation. The delay gives people time to act. |
The point of the deprecation is to emit a message so users are not surprised when it does go away. Likewise, if it is incompatible (which can be possible) but it does give a message, then that can make clear to the user that they need to change something at that time. |
That's not deprecation, that's an error message. |
If people is not notified somehow, what is the use of the delay? |
Deprecation messages are just one part of a communication strategy. Downstream developers stay informed about the projects that they use in various ways. |
Not in general. Plus, you need to be able to set the message, which you cannot do with, e.g., an |
It is getting vague... If "compatibility and (in-code) message" is not possible (as in the subclassing case), then some message (communication) should be posted somewhere at least. We may post these in the release note. I think (hope ?) that these deprecations of public classes are rare events. So this way of communication would not be burdensome... |
Well, deprecations should be noted already in the title of the PR that deprecates it, which will make it show up in the automatically generated release notes: https://github.com/sagemath/sage/releases/tag/10.1 Having a section on deprecations in release notes is a very standard practice. See for example https://docs.scipy.org/doc/scipy/release/1.13.0-notes.html#deprecated-features |
OK. It seems that posting deprecations of public classes in the "Deprecation" section of the release notes is the best we can do. So deprecation of public classes is done differently from the deprecation policy of functions/methods/attributes. |
Note that also for some aspects of our Cython interfaces we do not have any deprecation infrastructure other than code comments and release notes. (Edit: someone may have mentioned that already somewhere above) |
Back to "public and internal" discussion, we now have, as alternatives: (C) A class is internal if its name has an underscore anywhere is internal (CT) = (M') A function/method/attribute/class/etc. whose name starts with one or more underscores are considered internal or does not appear in the public documentation (the published html https://doc.sagemath.org/html/en/ or the corresponding pdf), and is not subject to the deprecation policy. (CL) A class is internal if its name starts with an underline or it cannot be importable from command line (CS) A class is internal if experts (reviewers for a PR) think so. If experts disagree, then it is public. People here give their preferences or suggest modifications or a new alternative. I will collect a couple of most preferred alternatives, and bring the discussion to sage-devel. |
Thanks for compiling the list. I like (CL) + (CS). |
I agree with (CL) + (CS). We could elaborate slightly on (CS) by saying |
Is my understanding correct that (CT) = (M') is a subset of (CL)? Anyways, I am +1 with (CT) + (CL) + (CS)/(CS'). FWIW (CS) has been the case in the past |
Actually as sets, probably they are the same, unless there is some module that is omitted in the documentation (perhaps by mistake). |
Regarding this point, it seems to me that for public classes that are not part of the global namespace, the best option is often to keep the old name as an alias forever. |
We may define the following standard procedures, from practices. (RNP) Procedure to rename a public class class NewClass:
....
OldClass = NewClass # OldClass is deprecated. See Issue 12345. (RNP step 2) before the next stable release, post the change to the "Deprecated" section of the release note. The alias will be there forever unless someone steps up to remove it :-) (RMP) Procedure to remove a public class # Class is deprecated. See Issue 12345.
class Class: (RMP step 2) before the next stable release, post the change to the "Deprecated" section of the release note. |
I think we are already converging to a consensus. So I will bring only the following items to sage-devel for wider discussion: (S) Only public functions, methods, attributes, classes living under (M) Functions, methods, attributes, classes whose names start with an underscore are considered internal, and is not subject to the deprecation policy. (C) A class whose name does not start with an underscore is public by default, but can be considered internal if experts agree that the class is unlikely to be directly imported by user code. If experts disagree, then it is public. For a PR changing the class, authors and reviewers are the experts. |
…xpElement`, `GroupSemidirectProductElement` <!-- ^ Please provide a concise and informative title. --> <!-- ^ Don't put issue numbers in the title, do this in the PR description below. --> <!-- ^ For example, instead of "Fixes sagemath#12345" use "Introduce new method to calculate 1 + 2". --> <!-- v Describe your changes below in detail. --> <!-- v Why is this change required? What problem does it solve? --> <!-- v If this PR resolves an open issue, please link to it here. For example, "Fixes sagemath#12345". --> `GroupExp_Class` as discussed in: - sagemath#38211 (comment) @saraedum Part of: - sagemath#25383 ### 📝 Checklist <!-- Put an `x` in all the boxes that apply. --> - [x] The title is concise and informative. - [ ] The description explains in detail what this PR is about. - [x] I have linked a relevant issue or discussion. - [ ] I have created tests covering the changes. - [ ] I have updated the documentation and checked the documentation preview. ### ⌛ Dependencies <!-- List all open PRs that this PR logically depends on. For example, --> <!-- - sagemath#12345: short description why this is a dependency --> <!-- - sagemath#34567: ... --> URL: sagemath#38238 Reported by: Matthias Köppe Reviewer(s): Kwankyu Lee
Problem Description
The Developer Guide, Section Deprecation does not specify if the deprecation process applies to semi-private (name starts with exactly one underscore) or private (name starts with exactly two underscores) callables (functions, methods, attributes, classes, etc).
Proposed Solution
I think the following two options are both valid:
Semi-private or private methods are for devs and are not part of the interface; users should not use them, which is a Python-wide convention, and the devs should not have to worry about keeping compatibility for semi-private and private callables.
However, it seems the developer guide deprecation process applies to those as well, and not all users are aware of the
_
and__
convention.Both options are fine to me and I believe this is a minor issue. However, I think the community should pick a single approach and make it somewhat official but explicitly putting it in the developer guide.
Alternatives Considered
See above.
Additional Information
No response
Is there an existing issue for this?
The text was updated successfully, but these errors were encountered: