cpython icon indicating copy to clipboard operation
cpython copied to clipboard

Document missing type flags as part of Stable ABI

Open da-woods opened this issue 1 month ago • 4 comments

The documentation is currently pretty inconsistent about listing the type flags as part of the Stable ABI. Some are listed and some aren't. I've hopefully got all the important ones.

I haven't done _Py_TPFLAGS_MATCH_SELF which is exposed in the Limited API but starts with an underscore.

I also haven't done things like Py_TPFLAGS_VALID_VERSION_TAG, Py_TPFLAGS_HAVE_FINALIZE, Py_TPFLAGS_HAVE_VERSION_TAG which are exposed in the Limited API but now don't do anything.

da-woods avatar Jan 02 '26 10:01 da-woods

I'll also note that object.h is pretty inconsistent about whether to guard flags with

#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0xVERSION

e.g. Py_TPFLAGS_HAVE_VECTORCALL is guarded, while Py_TPFLAGS_DISALLOW_INSTANTIATION, Py_TPFLAGS_IMMUTABLETYPE, Py_TPFLAGS_METHOD_DESCRIPTOR, and maybe some others, aren't guarded despite being recent additions. Practically that probably doesn't matter too much though.

da-woods avatar Jan 02 '26 10:01 da-woods

Per PEP 652, Limited API is defined by stable_abi.toml. The set definitions you get whith Py_LIMITED_API is an approximation of that.

Discrepancies can be bugs in either stable_abi.toml, or in the Py_LIMITED_API ifdefs. Which one? That's generally a question for the C API WG.

You're right that type flags are a mess. Most macros are :(

As the comment in stable_abi.toml says, flags are implicitly part of the ABI. But, they're not necessarily part of the Limited API. Note that PEP 652 specifically omits the 3.2 flags added by this PR, and includes Py_TPFLAGS_METHOD_DESCRIPTOR. There's a reason for the “inconsistency”,

IMO:

  • the *_SUBCLASS should not be included; you should use PyUnicode_Check and similar (which should be added to Limited API/Stable ABI if they're not there already).
  • READY & READYING shouldn't be included either -- AFAIK, this detail of the class creation machinery isn't that important for heap types, as there's no hooks to customize behaviour between allocation and the PyType_Ready call. We shouldn't need to expose the bits.
  • For DISALLOW_INSTANTIATION & IMMUTABLETYPE, we're probably stuck exposing them as flags. But, code that checks these, for something else than optimizations, is probably doing something wrong.

We probably need (soft-)deprecation for these, in a “have the cake” (don't blame Cython for doing something wrong) “and eat it too” (alternate implementations of the C API don't need to provide these) way.


exposed in the Limited API but starts with an underscore.

Nothing in the Limited API starts with an underscore :)

encukou avatar Jan 05 '26 14:01 encukou

(commented early by mistake.)

There's a reason for the “inconsistency”,

, but the reason is probably only in my head, and the working group needs to decide where this should be now on the spectrum between designing a more portable API & freezing the status quo.

encukou avatar Jan 05 '26 14:01 encukou

(don't blame Cython for doing something wrong)

Off the top of my head, I think Cython only uses DISALLOW_INSTANTIATION and IMMUTABLETYPE (in "set" mode rather than "check" mode). So I don't think we're doing much that should be disallowed. Trying to work out if I was actually allowed to be doing this was the main thing that prompted this PR.

I do agree with you that mostly type flags are properties you want to be able to set in the Stable ABI without necessarily caring that they're stored as a set of bits in the type object.

The one flag that it does check in (older) limited API is HEAP_TYPE because of the behaviour change of PyType_GetSlot. I'll assume that's also Ok for now.

I'll create a C API WG issue. Shall I change this PR to draft until that's decided?

da-woods avatar Jan 05 '26 17:01 da-woods

I'll create a C API WG issue. Shall I change this PR to draft until that's decided?

Thanks. Yeah, let's keep this a draft.

encukou avatar Jan 06 '26 15:01 encukou