cpu / pyfunction_getannotations_test

Testing difference between PyFunction_GetAnnotations in Python 3.9 and Python 3.10

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Archived

This regression was confirmed and fixed upstream w/ https://bugs.python.org/issue46236

PyFunction_GetAnnotations Test

There seems to be a change in Python 3.10's PyFunction_GetAnnotations C API return value compared to Python 3.9. This repo holds a small program that can be used to demonstrate the change between versions easily.

Test Usage

  1. Ensure you have both python3.10 and python3.9 installed and on your $PATH
  2. make pythonVersion="python3.9"
  3. ./main
  4. make clean
  5. make pythonVersion="python3.10"
  6. ./main

If you happen to have a working Nix install you can run nix-shell to have an environment created with both python3.10 and python3.9 ready to run the above steps.

Example Output

Demonstration

[nix-shell:~/Code/C/pyfunction_getannotations_test]$ make clean
rm -f *~ *.o main

[nix-shell:~/Code/C/pyfunction_getannotations_test]$ make
gcc -Wall -O0 -g -I/nix/store/jizav0w3q9gfszi3g059pm3crh4awnha-python3-3.10.0/include/python3.10 -I/nix/store/jizav0w3q9gfszi3g059pm3crh4awnha-python3-3.10.0/include/python3.10  -Wno-unused-result -Wsign-compare  -DNDEBUG -g -fwrapv -O3 -Wall   -c -o main.o main.c
gcc -Wall -O0 -g -I/nix/store/jizav0w3q9gfszi3g059pm3crh4awnha-python3-3.10.0/include/python3.10 -I/nix/store/jizav0w3q9gfszi3g059pm3crh4awnha-python3-3.10.0/include/python3.10  -Wno-unused-result -Wsign-compare  -DNDEBUG -g -fwrapv -O3 -Wall main.o -o main -lm  -L/nix/store/jizav0w3q9gfszi3g059pm3crh4awnha-python3-3.10.0/lib  -lpthread -ldl -lcrypt -lncurses -lutil -lm -lm  -lpython3.10

[nix-shell:~/Code/C/pyfunction_getannotations_test]$ ./main
PyFunction_GetAnnotations returned PyTuple

[nix-shell:~/Code/C/pyfunction_getannotations_test]$ make clean
rm -f *~ *.o main

[nix-shell:~/Code/C/pyfunction_getannotations_test]$ make pythonVersion="python3.9"
gcc -Wall -O0 -g -I/nix/store/wl02plhc6zf84m6x9984l42wnnnbly5m-python3-3.9.6/include/python3.9 -I/nix/store/wl02plhc6zf84m6x9984l42wnnnbly5m-python3-3.9.6/include/python3.9  -Wno-unused-result -Wsign-compare  -DNDEBUG -g -fwrapv -O3 -Wall   -c -o main.o main.c
gcc -Wall -O0 -g -I/nix/store/wl02plhc6zf84m6x9984l42wnnnbly5m-python3-3.9.6/include/python3.9 -I/nix/store/wl02plhc6zf84m6x9984l42wnnnbly5m-python3-3.9.6/include/python3.9  -Wno-unused-result -Wsign-compare  -DNDEBUG -g -fwrapv -O3 -Wall main.o -o main -lm  -L/nix/store/wl02plhc6zf84m6x9984l42wnnnbly5m-python3-3.9.6/lib  -lpthread -ldl -lcrypt -lncurses -lutil -lm -lm  -lpython3.9

[nix-shell:~/Code/C/pyfunction_getannotations_test]$ ./main
PyFunction_GetAnnotations returned PyDict

Analysis

With the same C code and the same Python program we see two different results from PyFunction_GetAnnotations depending on whether the program is linked with Python 3.10 or Python 3.9.

In the Python 3.10 case (presented first in the output) the PyFunction_GetAnnotations invocation returns a PyObject* that passes PyTuple_Check but not PyDict_Check.

In the Python 3.9 case (presented second in the output) the same invocation produces a PyObject* that passes PyDict_Check as expected.

The documentation for PyFunction_GetAnnotations for 3.10 says:

Return the annotations of the function object op. This can be a mutable dictionary or NULL

This seems to indicate it should always be a dictionary or NULL and a tuple is neither of these things. Is it a documentation bug? User error? A regression?

Root Cause Speculation

The Python 3.10 "What's New" announcement mentions an optimization that may be the cause of this change:

When using stringized annotations, annotations dicts for functions are no longer created when the function is created. Instead, they are stored as a tuple of strings, and the function object lazily converts this into the annotations dict on demand. This optimization cuts the CPU time needed to define an annotated function by half.

See also, Python issue42202.

About

Testing difference between PyFunction_GetAnnotations in Python 3.9 and Python 3.10


Languages

Language:C 66.3%Language:Makefile 19.3%Language:Nix 11.8%Language:Python 2.7%