- 3 participants
- 2 discussions
Leading uderscore in C-API names (`_Py`): Private, or just a warning?
by Petr Viktorin 20 Jun '22
by Petr Viktorin 20 Jun '22
20 Jun '22
(Rather obviously, I'm not writing on behalf of the SC.) The Steering Council's response to my PEP 689 (Unstable C API tier) opened a subtle question that I'd like to get some discussion on: What does it mean if an API has a leading underscore (i.e. the `_Py` prefix)? It seems that currently, the underscore serves as a “warning” -- its users (and reviewers) should read the documentation when using such functions. (This might be more nuanced; I'll leave any details to other people so I won't misinterpret their views.) I was surprised to learn that this is the status quo, and I don't think it's a good one. So I took what I thought is the status quo, tightened it, and I present it as a proposal: ## Proposal Anything that starts with `_Py` is a fully internal, private CPython implementation detail. As a user, you can use it in a debugging session but don't rely on it existing (or being compatible) in any different CPython release. That said: - We won't break this internal API for no reason, so if you use it now and have good tests you don't need stop using it right now. - If you're using private API and don't see a public alternative, you should contact CPython devs to - see if we can add public API for the use case. - let us know that someone's using the API, and we should be extra careful with it. With this rule, you can simply grep your codebase for `_Py` to see if you're using API that can go away without warning. I'm aware that there are currently many underscored names that are intended to be used. Under this proposal, we should eventually add non-underscores aliases for them to make their status clear. (That's a desired end state; there's no rush to get 100% there.) ## Underscore as a warning The alternative (underscore means “warning”, read the documentation) is, IMO, unfortunate. The documentation for underscored functions is often missing, both for functions you can use and ones you shouldn't. Consider example questions like: - `_PyCode_GetExtra` is mentioned in PEP 523, but not documented on docs.python.org. As a user, can I use it? - `_PyImport_AcquireLock` is mentioned in a StackOverflow answer, but not on docs.python.org. As a user, can I use it? - I find that (say) `_PyArg_UnpackStack` is no longer necessary in CPython. As a core dev, where do I need to look to see if I can remove it? The issues these point out can't be fixed easily: there are hundreds of underscored functions exposed in the public headers, and no good way to prevent adding new ones (of either kind -- consumable or private). Some API is even only exposed for technical reasons: `_Py_NewRef` needs to be exposed, even though we'd like users to never use it. (This particular function is not too dangerous to use, but any macro or `static inline` function that's an implementation detail has the same issue.) But there's no way for CPython to mark something in a public API header as private. Something that's undocumented on purpose is indistinguishable from something we forgot to document. There's no way to check a codebase for using internal API, short of manually checking the docs of each function.
Re: Leading uderscore in C-API names (`_Py`): Private, or just a warning?
by Marc-Andre Lemburg 14 Jun '22
by Marc-Andre Lemburg 14 Jun '22
14 Jun '22
On 14.06.2022 11:54, Petr Viktorin wrote: > On 14. 06. 22 11:35, Marc-Andre Lemburg wrote: >> On 14.06.2022 11:15, Petr Viktorin wrote: >>> On 13. 06. 22 17:36, Marc-Andre Lemburg wrote: >>>> In the past we always said: "_Py* is an internal API. Use at your own >>>> risk.", which I guess is somewhere between the warning and the strict >>>> "don't use" policy you are describing. >>>> >>>> The problem with the "don't use" policy is that in some cases, there >>>> are no public APIs available to do certain things and so the extension >>>> writers have to resort to the private ones to implement their logic. >>>> >>>> E.g. to implement a free list for Python objects, you have to use >>>> _Py_NewReference() in order to create an object based on a memory >>>> area taken from the free list. If you want to create a bytes objects >>>> using overallocation, it's common to use _PyBytes_Resize() to resize >>>> the buffer to the final size. >>>> >>>> What sometimes happens is that after a while the private APIs get their >>>> leading underscore removed to then become public ones. >>> >>> It's not just about removing the underscore: when this happens the APIs should >>> also get documentation, tests, and some expectation of stability (e.g. that we >>> won't go randomly adding tstate parameters to them). >> >> Of course; all public APIs should ideally have this :-) >> >>>> This upwards >>>> migration path would be made impossible with the "don't use" policy. >>> >>> Why not? I have no doubt people will use private API, no matter how explicitly >>> we say that it can break at any time. >>> >>> My proposal is making this more explicit. And yes, it's also putting some more >>> pressure on core devs to expose proper API for use cases people have, and on >>> people to report their use cases. >> >> It would certainly be good to get more awareness for common uses of >> currently private APIs, but I'm not sure whether the proposed >> "don't use" policy would help with this. >> >> I have a feeling that the effect would go in a different direction: >> with a strict "don't use" policy core devs would get a blanket >> permission to change exposed _Py* APIs at will, without any consideration >> about breaking possible use cases out there. >> >> IMO, both parties should be aware of the issues around using/changing >> exposed APIs marked as private and ideally to the same extent. > > OK, but what are those issues? How do we get to the point where both parties > agree? We don't even know who the other party is. > >> Perhaps it would be better to leave the current "use at your own risk" >> approach in place and just add a new process for potentially having >> private APIs made public. > > But if we say "use at your own risk", what's the risk? Isn't that the same as > saying we don't support it at all and it might go away at any time? Not really, since the bar for core devs is higher when making changes to such internal APIs. A blanket "don't use" policy would make it easy for core devs to argue that any change is acceptable. If we provide a process to document external use of currently private APIs, both sides get to know each other and their use cases. The "risk" for the external developer is that the APIs may not get approved as public APIs. The process itself allows core devs to get a view into the use of those APIs and take more care when making changes to those APIs while the process of potentially making them public is still ongoing. Overall, we'd get a better idea on what extension writers need, while at the same it'd be clearer which of the private APIs can indeed be changed without causing disruption. If we say: please open a ticket when starting to use a private API, I think we'd get to a better C API in the long run. >> E.g. the above two cases are potentially candidates for such a >> process. I have used both in code I have written, because, AFAIK, >> there's no other way to implement the functionality otherwise. >> >> I'm pretty sure that fairly low level tools such as Cython will >> have similar cases. > > Indeed. Documenting and testing _Py_NewReference and its caveats sounds like a > good idea, and we might as well remove the underscore then. -- Marc-Andre Lemburg eGenix.com Professional Python Services directly from the Experts (#1, Jun 14 2022) >>> Python Projects, Coaching and Support ... https://www.egenix.com/ >>> Python Product Development ... https://consulting.egenix.com/ ________________________________________________________________________ ::: We implement business ideas - efficiently in both time and costs ::: eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48 D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg Registered at Amtsgericht Duesseldorf: HRB 46611 https://www.egenix.com/company/contact/ https://www.malemburg.com/