On Sat, Aug 14, 2021 at 4:56 AM Serhiy Storchaka <storchaka@gmail.com> wrote:
13.08.21 20:24, Guido van Rossum пише:
> If these weren't part of the stable ABI, I'd choose (E). But because
> they are, I think only (A) or (B) are our options. The problem with (C)
> is that if there's code that links to them but doesn't call them (except
> in some corner case that the user can avoid), the code won't link even
> though it would work fine. The problem with (D) is that if it *is*
> called by code expecting the old signature it will segfault. I'm not
> keen on (A) since it can cause broken code objects when used to copy a
> code object with some modified metadata (e.g. a different filename),
> since there's no way to pass the exception table (and several other
> fields, but the exception table is an integral part of the code now).

I agree that (A) and (B) are only options if we preserve binary
compatibility. For practical reasons I prefer (B).

We can make (A) working if add the exception table to the end of the
bytecode array and the endline/column tables to the end of the lineno
table. It would allow to re-construct the code object with some simple
changes (like filename or replace some constants). Creating the code
object from zero is version-specific in any case, because bytecode is
changed in every version, and semantic of some fields can be changed too
(e.g. support of negative offsets in the lineno table). But it would
complicate the code object structure and the code that works with it in
long term.

That sounds like a perversion of backward compatibility. The endline and column tables are already optional (there's a flag to suppress them and then the fields are set to None) and we can just not support code that catches exceptions. If you take e.g.

def f(x):
    try:
        1/0
    except:
        print("NO")

and you remove the exception table you get code that is equivalent to this:

def f(x):
    1/0

plus some unreachable bytecode.

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.

--
--Guido van Rossum (python.org/~guido)