Skip to content

PyUnstable_ExecutableKinds is useless #152105

Description

@ZeroIntensity

We have some unstable APIs related to frame executables. We were looking into documenting them in #143490. These are defined at the bottom of frame.c:

cpython/Python/frame.c

Lines 153 to 159 in 0fb82b4

const PyTypeObject *const PyUnstable_ExecutableKinds[PyUnstable_EXECUTABLE_KINDS+1] = {
[PyUnstable_EXECUTABLE_KIND_SKIP] = &_PyNone_Type,
[PyUnstable_EXECUTABLE_KIND_PY_FUNCTION] = &PyCode_Type,
[PyUnstable_EXECUTABLE_KIND_BUILTIN_FUNCTION] = &PyMethod_Type,
[PyUnstable_EXECUTABLE_KIND_METHOD_DESCRIPTOR] = &PyMethodDescr_Type,
[PyUnstable_EXECUTABLE_KINDS] = NULL,
};

The idea is that users can use these to determine the type of f_executable without accessing it -- but it seems we forgot to add an API to actually get one of the PyUnstable_EXECUTABLE_KIND* macros from a frame object! That means the only way to an entry out of PyUnstable_ExecutableKinds is to know the type in advance, like this:

int
get_executable_kind(PyFrameObject *frame)
{
    _PyInterpreterFrame *f = frame->f_frame;
    PyObject *exec = PyStackRef_AsPyObjectBorrow(f->f_executable);

    if (PyCode_Check(exec)) {
        return PyUnstable_EXECUTABLE_KIND_PY_FUNCTION;
    }
    if (PyMethod_Check(exec)) {
        return PyUnstable_EXECUTABLE_KIND_BUILTIN_FUNCTION;
    }
    if (Py_IS_TYPE(exec, &PyMethodDescr_Type)) {
        return PyUnstable_EXECUTABLE_KIND_METHOD_DESCRIPTOR;
    }

    return PyUnstable_EXECUTABLE_KIND_SKIP;
}

But, if you already know the type, then you have no reason to access PyUnstable_ExecutableKinds! For the future, let's decide on one of two options:

  1. If this is still intended to be useful, then let's add the get_executable_kind function described above as an unstable C API.
  2. Otherwise, let's just remove this in 3.16.

cc @markshannon (author of #105727, where these were added), @encukou

Linked PRs

Activity

  1. ZeroIntensity commented on Jun 24, 2026

    @ZeroIntensity
    MemberAuthor

    cc @vstinner as well (author of #108440)

  2. encukou commented on Jun 25, 2026

    @encukou
    Member

    I have no idea -- from #105727 I can't figure out how this should be used and why it's needed.
    cc @iritkatriel, as the reviewer.

  3. encukou commented on Jun 25, 2026

    @encukou
    Member

    Oh, here's a hint: #108651 (comment)

    These constants are intended for tools like pyspy and austin, which are out-of-process tools.
    They need to copy and paste the constants, so it doesn't matter to them whether they are private or unstable.
    However, they could be useful for in-process tools as well, so making them "unstable" seems best.

    But, I could find no mention of ExecutableKinds in py-spy and austin.

  4. zainnadeem786 commented on Jun 29, 2026

    @zainnadeem786
    Contributor

    Hi @ZeroIntensity

    I investigated this on current main.

    From what I found, PyUnstable_ExecutableKinds appears to be declared and defined, but not actually usable in practice:

    • I found no in-tree users besides its declaration/definition.
    • I found no tests or documentation covering it.
    • I could not find an API that maps a PyFrameObject to a PyUnstable_EXECUTABLE_KIND_* value.
    • The named external tools discussed previously, py-spy and Austin, do not appear to use PyUnstable_ExecutableKinds or the PyUnstable_EXECUTABLE_KIND_* constants.

    Given that, I think the current API is effectively orphaned. My preference would be to remove PyUnstable_ExecutableKinds in 3.16 unless there is interest in reviving the broader non-code executable frame design from gh-100987.

    I’m happy to prepare a small removal PR if that direction sounds reasonable ?

  5. encukou commented on Jun 29, 2026

    @encukou
    Member

    @zainnadeem786, you've only repeated what's already covered above.
    We are waiting for a comment by the people who added the API.

  6. zainnadeem786 commented on Jun 29, 2026

    @zainnadeem786
    Contributor

    Thanks for the clarification @encukou . I'll wait for the original design discussion before proposing any changes.

  7. ZeroIntensity commented on Jun 29, 2026

    @ZeroIntensity
    MemberAuthor

    @zainnadeem786 When triaging, I encourage you to use your own words and judgment rather than feeding an issue into an LLM. I've noticed this kind of response is a common pattern with your contributions. We are humans; we prefer to talk to other humans too.

  8. zainnadeem786 commented on Jun 29, 2026

    @zainnadeem786
    Contributor

    Thanks for the feedback, @ZeroIntensity.

    I appreciate it.

    For my investigations, I always reproduce the issue locally, inspect the relevant code, and verify my conclusions before commenting. I realize my comment came across more like a summary than my own reasoning, and I'll do a better job of emphasizing my own analysis and observations in future discussions.

    Thanks for the guidance.

  9. added 4 commits that reference this issue on Aug 5, 2026
  10. encukou commented on Aug 6, 2026

    @encukou
    Member

    Removed in #155244. If anyone has more info we can reopen.

  11. added a commit that references this issue on Aug 7, 2026
  12. added 2 commits that reference this issue on Aug 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions