You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[C API] Make the PyDescrObject structure opaque: PyDescr_NAME() and PyDescr_TYPE() #90696
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee=Noneclosed_at=<Date2022-01-26.16:23:19.541>created_at=<Date2022-01-26.16:14:46.779>labels= ['expert-C-API', '3.11']
title='[C API] Make the PyDescrObject structure opaque: PyDescr_NAME() and PyDescr_TYPE()'updated_at=<Date2022-01-26.16:35:59.571>user='https://github.com/vstinner'
While working on the PEP-674 implementation, I noticed that PyDescr_NAME() and PyDescr_TYPE() macros are used as l-value by two projects: M2Crypto and mecab-python3. Both are code generated by SWIG.
M2Crypto-0.38.0/src/SWIG/_m2crypto_wrap.c and mecab-python3-1.0.4/src/MeCab/MeCab_wrap.cpp contain the function:
SwigPyStaticVar_new_getset() is more of less an outdated copy of Python 2.7 descr_copy() of Python Objects/descrobject.c.
I tried to prevent using the PyDescr_NAME() and PyDescr_TYPE() macros as l-value in two ways:
Add PyDescr_SET_NAME() and PyDescr_SET_Type()
Add PyDescr_New()
The problem of the PyDescr_SET_NAME() and PyDescr_SET_Type() approach is that SWIG code is outdated: it doesn't initialized the PyDescrObject.d_qualname member added to Python 3.3 (bpo-13577, commit 9d57481).
So I implemented PyDescr_New() function: in CPython, it means basically to rename descr_new() to PyDescr_New(). Problem: implementating this function for older Python versions is non trivial. Code that I wrote for the pythoncapi_compat project:
The even more complicated part is to write unit tests for this function in pythoncapi_compat. It requires to implement a whole type with tp_traverse tp_dealloc functions.
In Python, this function must be at least documented.
At the end, IMO it's not really worth it to add so much complexity to Python and pythoncapi_compat just for 2 projects using SWIG. I created this issue to keep a track of my analysis, if someone else tries to do something similar tomorrow.
I attached my WIP patches to keep a copy of this work, in case if we need to revisit this idea later.
For the PEP-674, IMO it's better to leave the two PyDescr_NAME() and PyDescr_TYPE() macros unchanged. There is no need in the short term to make PyDescrObject structure and structures using it opaque in the short term. Well, SWIG code looks incorrect (it doesn't initialize d_qualname), but a fix just for SWIG should be enough.
The problem of the PyDescr_SET_NAME() and PyDescr_SET_Type() approach is that SWIG code is outdated: it doesn't initialized the PyDescrObject.d_qualname member added to Python 3.3 (bpo-13577, commit 9d57481).
I checked: Oh, in practice, it's not an issue since PyType_GenericAlloc() initializes the memory to zero. So the code "just works".
changed the title [-][C API] Make the PyDescrObject structure opaque[/-][+][C API] Make the PyDescrObject structure opaque: PyDescr_NAME() and PyDescr_TYPE()[/+]on Jan 26, 2022
changed the title [-][C API] Make the PyDescrObject structure opaque[/-][+][C API] Make the PyDescrObject structure opaque: PyDescr_NAME() and PyDescr_TYPE()[/+]on Jan 26, 2022
Activity
vstinner commentedon Jan 26, 2022
While working on the PEP-674 implementation, I noticed that PyDescr_NAME() and PyDescr_TYPE() macros are used as l-value by two projects: M2Crypto and mecab-python3. Both are code generated by SWIG.
M2Crypto-0.38.0/src/SWIG/_m2crypto_wrap.c and mecab-python3-1.0.4/src/MeCab/MeCab_wrap.cpp contain the function:
SWIGINTERN PyGetSetDescrObject *
SwigPyStaticVar_new_getset(PyTypeObject *type, PyGetSetDef *getset) {
ref: https://bugs.python.org/issue45476#msg407410
SwigPyStaticVar_new_getset() is more of less an outdated copy of Python 2.7 descr_copy() of Python Objects/descrobject.c.
I tried to prevent using the PyDescr_NAME() and PyDescr_TYPE() macros as l-value in two ways:
The problem of the PyDescr_SET_NAME() and PyDescr_SET_Type() approach is that SWIG code is outdated: it doesn't initialized the PyDescrObject.d_qualname member added to Python 3.3 (bpo-13577, commit 9d57481).
So I implemented PyDescr_New() function: in CPython, it means basically to rename descr_new() to PyDescr_New(). Problem: implementating this function for older Python versions is non trivial. Code that I wrote for the pythoncapi_compat project:
The even more complicated part is to write unit tests for this function in pythoncapi_compat. It requires to implement a whole type with tp_traverse tp_dealloc functions.
In Python, this function must be at least documented.
At the end, IMO it's not really worth it to add so much complexity to Python and pythoncapi_compat just for 2 projects using SWIG. I created this issue to keep a track of my analysis, if someone else tries to do something similar tomorrow.
I attached my WIP patches to keep a copy of this work, in case if we need to revisit this idea later.
For the PEP-674, IMO it's better to leave the two PyDescr_NAME() and PyDescr_TYPE() macros unchanged. There is no need in the short term to make PyDescrObject structure and structures using it opaque in the short term. Well, SWIG code looks incorrect (it doesn't initialize d_qualname), but a fix just for SWIG should be enough.
vstinner commentedon Jan 26, 2022
pydescr_set_type.patch: Python patch to add PyDescr_SET_TYPE() and PyDescr_SET_NAME() functions.
vstinner commentedon Jan 26, 2022
pydescr_new.patch: Python patch adding the PyDescr_New() function.
vstinner commentedon Jan 26, 2022
pythoncapi_compat_pydescr_new.patch: pythoncapi_compat patch adding PyDescr_New() function with tests.
vstinner commentedon Jan 26, 2022
swig_pydescr_new.patch: SWIG patch adding PyDescr_New() and using it.
vstinner commentedon Jan 26, 2022
Since making PyDescrObject opaque is not really worth it, I close this issue.
I mean, it's worth it, but there are more important structures like PyObject, PyTypeObject or PyListObject.
vstinner commentedon Jan 26, 2022
I checked: Oh, in practice, it's not an issue since PyType_GenericAlloc() initializes the memory to zero. So the code "just works".
[-][C API] Make the PyDescrObject structure opaque[/-][+][C API] Make the PyDescrObject structure opaque: PyDescr_NAME() and PyDescr_TYPE()[/+][-][C API] Make the PyDescrObject structure opaque[/-][+][C API] Make the PyDescrObject structure opaque: PyDescr_NAME() and PyDescr_TYPE()[/+]