upgrade_pythoncapi.py script

upgrade_pythoncapi.py requires Python 3.6 or newer.


Run the with no arguments to display command line options and list available operations:

python3 upgrade_pythoncapi.py

Select files and directories

To upgrade module.c file, type:

python3 upgrade_pythoncapi.py module.c

To upgrade all C and C++ files (.c, .h, .cc, .cpp, .cxx and .hpp files) in the directory/ directory, type:

python3 upgrade_pythoncapi.py directory/

Multiple filenames an directories can be specified on the command line.

Files are modified in-place! If a file is modified, a copy of the original file is created with the .old suffix.

Select operations

To only replace op->ob_type with Py_TYPE(op), select the Py_TYPE operation with:

python3 upgrade_pythoncapi.py -o Py_TYPE module.c

Or the opposite, to apply all operations but leave op->ob_type unchanged, deselect the Py_TYPE operation with:

python3 upgrade_pythoncapi.py -o all,-Py_TYPE module.c

Download pythoncapi_compat.h

Most upgrade_pythoncapi.py operations add #include "pythoncapi_compat.h". You may have to download the pythoncapi_compat.h header file to your project. It can be downloaded with:

python3 upgrade_pythoncapi.py --download PATH

Upgrade Operations

upgrade_pythoncapi.py implements the following operations:


  • Replace op->ob_type with Py_TYPE(op).


  • Replace op->ob_size with Py_SIZE(op).


  • Replace op->ob_refcnt with Py_REFCNT(op).


  • Replace obj->ob_type = type; with Py_SET_TYPE(obj, type);.

  • Replace Py_TYPE(obj) = type; with Py_SET_TYPE(obj, type);.


  • Replace obj->ob_size = size; with Py_SET_SIZE(obj, size);.

  • Replace Py_SIZE(obj) = size; with Py_SET_SIZE(obj, size);.


  • Replace obj->ob_refcnt = refcnt; with Py_SET_REFCNT(obj, refcnt);.

  • Replace Py_REFCNT(obj) = refcnt; with Py_SET_REFCNT(obj, refcnt);.


  • Replace x == Py_None with Py_IsNone(x).

  • Replace x == Py_True with Py_IsTrue(x).

  • Replace x == Py_False with Py_IsFalse(x).

  • Replace x != Py_None with !Py_IsNone(x).

  • Replace x != Py_True with !Py_IsTrue(x).

  • Replace x != Py_False with !Py_IsFalse(x).


  • Replace PyObject_NEW(...) with PyObject_New(...).

  • Replace PyObject_NEW_VAR(...) with PyObject_NewVar(...).


  • Replace PyMem_MALLOC(n) with PyMem_Malloc(n).

  • Replace PyMem_REALLOC(ptr, n) with PyMem_Realloc(ptr, n).

  • Replace PyMem_FREE(ptr), PyMem_DEL(ptr) and PyMem_Del(ptr) . with PyMem_Free(n).


  • Replace PyObject_MALLOC(n) with PyObject_Malloc(n).

  • Replace PyObject_REALLOC(ptr, n) with PyObject_Realloc(ptr, n).

  • Replace PyObject_FREE(ptr), PyObject_DEL(ptr) and PyObject_Del(ptr) . with PyObject_Free(n).


  • Replace frame->f_back with _PyFrame_GetBackBorrow(frame).


  • Replace frame->f_code with _PyFrame_GetCodeBorrow(frame).


  • Replace tstate->interp with PyThreadState_GetInterpreter(tstate).


  • Replace tstate->frame with _PyThreadState_GetFrameBorrow(tstate).

Experimental operations

The following operations are experimental (ex: can introduce compiler warnings) and so not included in the all group, they have to be selected explicitly. Example: -o all,Py_SETREF.

Experimental operations:

  • Py_NewRef:

    • Replace Py_INCREF(res); return res; with return Py_NewRef(res);

    • Replace x = y; Py_INCREF(x); with x = Py_NewRef(y);

    • Replace x = y; Py_INCREF(y); with x = Py_NewRef(y);

    • Replace Py_INCREF(y); x = y; with x = Py_NewRef(y);

  • Py_CLEAR:

    • Replace Py_XDECREF(var); var = NULL; with Py_CLEAR(var);

  • Py_SETREF:

    • Replace Py_DECREF(x); x = y; with Py_SETREF(x, y);

    • Replace Py_XDECREF(x); x = y; with Py_XSETREF(x, y);