On Tue, 17 Aug 2021, 4:30 am Guido van Rossum, <guido@python.org> wrote:
On Mon, Aug 16, 2021 at 9:30 AM Steve Dower <steve.dower@python.org> wrote:
On 8/16/2021 12:47 AM, Guido van Rossum wrote:
> My current proposal is to issue a DeprecationWarning in PyCode_New() and
> PyCode_NewWithPosArgs(), which can be turned into an error using a
> command-line flag. If it's made an error, we effectively have (B); by
> default, we have (A).
>
> Then in 3.13 we can drop them completely.

We definitely had legitimate use cases come up when adding positional
arguments (hence the new API, rather than breaking the existing one,
which was the first attempt at adding the feature).

I don't recall exactly what they are (perhaps Pablo does, or they may be
in email/issue archives), but since they exist, presumably they are
useful and viable _despite_ the bytecode varying between releases. This
suggests there's probably a better API we should add at the same time -
possibly some kind of unmarshalling or cloning-with-updates function?

I presume the use cases are essentially some variant of the .replace() API that exists at the Python level. At the C level you would get all fields from an existing code object and pass them to PyCode_New[WithPosArgs] except for e.g. the co_filename field. Unfortunately those use cases will still break if there are any try blocks in the code or if the endline/column info is needed. Also you can't access any of the code object's fields without the internal API (this wasn't always so). So I think it's different now.

A cloning-with-replacement API that accepted the base code object and the "safe to modify" fields could be a good complement to the API deprecation proposal.

Moving actual "from scratch" code object creation behind the Py_BUILD_CORE guard with an underscore prefix on the name would also make sense, since it defines a key piece of the compiler/interpreter boundary.

Cheers,
Nick.

P.S. Noting an idea that won't work, in case anyone else reading the thread was thinking the same thing: a "PyType_FromSpec" style API won't help here, as the issue is that the compiler is now doing more work up front and recording that extra info in the code object for the interpreter to use. There is no way to synthesise that info if it isn't passed to the constructor, as it isn't intrinsically recorded in the opcode sequence.