PEP 387: backwards compatibilty policy

Regarding the (public) C-API, AFAIK we are already quite conservative in changes there, rarely break API compatibility, and mostly already follow PEP 387 (though the ability to emit deprecation warnings is limited for some classes of change). So for the most part I don’t think much will change relative to the C-API. There’s one main exception: making some currently public API “internal”.

For reference, we have already been working to set clear expectations regarding API stability (at least structural) in the C-API:

  • Include/*.h - “stable” API + Python.h; forward-compatible between minor releases; preprocessor checks on version guard backward compatibility; binary-compatible between minor releases
  • Include/cpython/*.h - “public” API; at most minimal backward-incompatible API changes; requires re-compiling for each minor version; no binary compatibility guarantees
  • Include/internal/*.h - use-at-your-own-peril (no guarantee of API stability)

(FWIW, I think community expectations for the stability of Python code align more closely with the stable C-API than with the full public C-API. With Python code and the stable API/ABI, you upgrade your Python installation and get back to work. However, with the public C-API you have to re-compile. So each minor release is already a disruption. As part of that process, (structural) incompatibility (as uncommon as it may be) surfaces through compiler errors rather than at runtime. That necessarily changes how folks react to incompatibility.)

Incompatible changes in the C-API can be grouped like this:

  1. change an existing signature/type (we basically never do this, instead adding “Ex”, etc. variants)
  2. change behavior (we avoid this and rarely do it)
  3. reduce a function/type’s “stability level” (move it from Include/ to Include/cpython/ or Include/cpython/ to Include/internal/)
  4. like (3) but make the type opaque at the previous stability level
  5. remove a function completely (uncommon and basically we always follow proper deprecation)

So, again, I don’t think that much will change relative to PEP 387. The recent notable cases of compatibility breaks are where we are trying to “fix” the C-API, mostly groups (3) and (4). That is the topic of the python-dev thread Paul mentioned above.

4 Likes

I’m scheduling the acceptance of this PEP in a week as things have settled down here and I believe the PEP addresses everyone’s concerns (and mine as PEP delegate :slight_smile:) . If you have a new concern which has not been brought up yet then please do so now.

1 Like

In case of C API, is runtime deprecation (e.g. raising DeprecationWarning) required, or is compiler warning enough?

For example, PyLong_FromUnicode is deprecated at document since Python 3.3 and compiler warning was added in Python 3.7. (ref)

Based on this policy, can we remove it in Python 3.10, or should we raise DeprecationWarning and wait at least two more releases?

In my opinion, raising DeprecationWarning in C API should be optional. When it seems safe, we can just remove it, or just have one release with runtime warning.

I would say the compiler warning is enough of a deprecation.

If you had a compiler warning being raised then yes, I agree. But if a compiler warning isn’t possible then I don’t think I agree you should skip the runtime warning.

Thank you for updating the PEP.

Yes, but I think it is still “best effort”, not a strict requirement.

Some C APIs are expected that doesn’t call arbitrary code. (e.g. compare arbitrary object, releasing GIL, etc). But arbitrary code is executed while emitting warning (e.g. warning filter). It can be a serious backward compatibility issue. It may cause segfault which is not easy to reproduce in multi threaded applications. So emitting warning from C is much harder than from Python.

When we can not use Py_DEPRECATED macro (e.g. removing specific behavior, but not API itself), runtime warning is strongly preferred. But if it is not safe, deprecation in document and comment should be allowed.

Compiler warnings are also acceptable.

But compiler warnings are compiler-dependent, and AFAICS, Py_DEPRECATED doesn’t warn on all supported compilers. Isn’t that a problem?

Is there a list of supported compilers?
Py_DEPRECATED is implemented for gcc, clang, and msvc.
It covers most extensions on PyPI.

I don’t think so.

Nope, just what we test against in CI.

We can’t support all compilers just like we can’t support all OSs. If someone chose to use an esoteric compiler and to never use a mainstream one to check for issues then that’s their choice, but I don’t see why it’s then our problem that the compiler isn’t supported for warnings.

1 Like

That makes sense, but IMO it would be good to make it explicit. Maybe something like:

C compiler warnings are also acceptable: use Py_DEPRECATED or make sure the warning appears with all major compilers: gcc, clang and msvc.

The problem with that statement is now PEP 387 is suddenly dictating what the officially supported compilers of Python are.

PEP 7 already specifies the C dialect for "major compilers but purposefully does not enumerate that list. If there ever was going to be a list then I would expect it to be there.

For compilation/behavior errors, a list of supported compilers isn’t really necessary: we support the language dialect, not individual compilers.
But warnings are not part of the dialect. Also, a lack of warnings is not noticeable, and not tested in CI.

The section " Making Incompatible Changes, reads like a best practices checklist for contributors. IMO, “check more than just your own compiler” is a good step to add. Maybe it can be done without looking like the definitive list of supported compilers?

C compiler warnings are also acceptable; use Py_DEPRECATED or make sure the warning appears with all major compilers.

Others can weigh in, but I feel like we are getting too prescriptive with this. We have mechanisms in place for raising warnings and people should use them. We don’t say what sort of warnings functions to call, just that you should raise a warning.

The SC met today and we agreed to accept PEP 387! I just marked it as Active and will be sending out the announcement email shortly.

6 Likes