Skip to content

Conversation

@vstinner
Copy link
Member

@vstinner vstinner commented Nov 17, 2025

Add a PyUnstable API for PEP 523:

  • PyUnstable_FrameEvalFunction type
  • PyUnstable_InterpreterState_GetEvalFrameFunc()
  • PyUnstable_InterpreterState_SetEvalFrameFunc()

Keep the old names as deprecated aliases to new names:

  • _PyFrameEvalFunction
  • _PyInterpreterState_GetEvalFrameFunc
  • _PyInterpreterState_SetEvalFrameFunc

Add PyUnstable API for PEP 523:

* PyUnstable_FrameEvalFunction type
* PyUnstable_InterpreterState_GetEvalFrameFunc()
* PyUnstable_InterpreterState_SetEvalFrameFunc()

Keep the old names as deprecated aliases to new names:

* _PyFrameEvalFunction
* _PyInterpreterState_GetEvalFrameFunc
* _PyInterpreterState_SetEvalFrameFunc
@efimov-mikhail
Copy link
Member

Do we need tests on PyUnstable API?

@vstinner
Copy link
Member Author

Do we need tests on PyUnstable API?

There are tests in test_optimizer: see _testinternalcapi.set_eval_frame_default().

@efimov-mikhail
Copy link
Member

efimov-mikhail commented Nov 17, 2025

Do we need tests on PyUnstable API?

There are tests in test_optimizer: see _testinternalcapi.set_eval_frame_default().

Thanks!
But it's only on PyUnstable_InterpreterState_SetEvalFrameFunc.
Maybe we want to test PyUnstable_InterpreterState_GetEvalFrameFunc a little?

@vstinner
Copy link
Member Author

Maybe we want to test PyUnstable_InterpreterState_GetEvalFrameFunc a little?

I added tests.

Co-authored-by: Mikhail Efimov <efimov.mikhail@gmail.com>
@vstinner
Copy link
Member Author

cc @emmatyping

Copy link
Member

@emmatyping emmatyping left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One question but otherwise looks good!

@vstinner
Copy link
Member Author

I created a C API Working Group decision issue.



static PyObject *
noop_eval(PyThreadState *tstate, struct _PyInterpreterFrame *f, int exc)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't _PyInterpreterFrame, need a public name too? Otherwise you can't quite use the functions without private API.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To implement an eval function, you should likely use the internal C API (pycore_interpframe.h) to access frame members, you're right. I don't want to add _PyInterpreterFrame structure members to the PyUnstable API, it's too unstable :-D I prefer to leave it in the internal C API.

I don't think that it's worth it to expose struct _PyInterpreterFrame* type in the PyUnstable API. What do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These functions are rather useless without making _PyInterpreterFrame public. At least should be an opaque type, with a function to upgrade it to the full PyFrameObject.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The API changed in Python 3.11 to take a _PyInterpreterFrame* instead of a PyFrameObject*. It's basically only used by PyTorch Dynamo which already uses the internal C API:

https://github.com/pytorch/pytorch/blob/be33b7faf685560bb618561b44b751713a660337/torch/csrc/dynamo/eval_frame.c#L15-L17

I wouldn't say that this API is useless without a public API for _PyInterpreterFrame*. It's just "unusual" :-)

At least should be an opaque type, with a function to upgrade it to the full PyFrameObject.

It would make the code (way) slower, _PyInterpreterFrame* idea is to avoid creating a concrete Python object for a frame unless it's strictly needed. I suggest using the internal C API for _PyInterpreterFrame* instead.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't say that this API is useless without a public API for _PyInterpreterFrame*.

What is the use, then?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@emmatyping @efimov-mikhail: Do you have an opinion on these questions?

Copy link
Member

@efimov-mikhail efimov-mikhail Nov 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, the main idea of this change is not really to make those functions public. We mark them as PyUnstable_ for sending clear message to its users: "we remember about those function, we don't want to change or remove them in the near future". One can use them and rely on their presence in C API, but can't rely on stability of _PyInterpreterFrame structure. So, there's a need to use some private headers in this case.

I agree that it's not the perfect position for us, but current situation isn't any better.
We have functions that both private and public.
They're private, because they have _Py* names.
But they're "kinda public", since PEP 523 is guaranteed their presence.
PyUnstable_ suits better for those semi-public functions.
But making _PyInterpreterFrame and all its members PyUnstable_ too seems redundant to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants