In Python 3.13, the private _Py_Identifier API was removed: see PR #108593.
Replacements:
- Use a literal bytes string: replace
&PyId_abc with "abc", use "String" variant functions. Slower, but works on all Python versions. This solution can be used on code which is not performance sensitive.
- Initialize a global or "static" variable to only create a Python str object once using
PyUnicode_FromString(): less convenient, not compatible with multi-phase init API (PEP 489), not compatible with PEP 684 – A Per-Interpreter GIL.
If we want to add a public API for this, I would prefer to only add the bare minimum API, make it as small as possible:
Py_IDENTIFIER(name) macro.
PyUnicode_FromId(&PyId_name) function.
Py_Identifier structure with public members (needed by Py_IDENTIFIER() macro).
- Maybe also:
Py_static_string(name, "...") macro for strings which are not valid C identifiers.
It means that _PyObject_GetAttrId(obj, &PyId_abc) must be replaced with:
PyObject *name = PyUnicode_FromId(&Py_abc);
if (name == NULL) { ... handle error... }
attr = PyObject_GetAttr(obj, name);
Since functions like PyObject_GetAttr() don't accept NULL, so you cannot simply write:
attr = PyObject_GetAttr(obj, PyUnicode_FromId(&Py_abc));
See discussion: