aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Tismer <tismer@stackless.com>2021-10-29 12:33:24 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2022-02-10 23:06:36 +0000
commit18a93ae18a486c2d49427186f72c88453a55d024 (patch)
tree77ec504a7c70062c7b53de3868e201bf1ac46e7b
parent47372eb977d9a480eb7b08290dff5c419acb44ee (diff)
__feature__: Fix snake_case handling on user defined classes
The snake case feature filters candidate methods and turns them into snake case. This works fine for built-in classes. The assumption is that all methods come from the tp_methods list. This assumption is not correct when applied to user defined classes. The methods have no static source in this case. To distinguish here, we inspect the tp_methods list. If it is empty, we assume a user defined class and do nothing. A forgotten initialization in feature.py was added, too. As a note: RHEL has such an old Python version that does not have MethodDescriptorType in the types module. [ChangeLog][PySide6] snake_case handling now does explicitly not touch user defined classes. Fixes: PYSIDE-1702 Change-Id: Idfa16cdc50cb7234c1d2f473dfae3a568887547e Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io> (cherry picked from commit 42695262f0ab4c73377b9d638dd28636ab1a3668) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--sources/pyside6/libpyside/feature_select.cpp22
-rw-r--r--sources/pyside6/tests/QtCore/snake_prop_feature_test.py30
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/feature.py1
3 files changed, 47 insertions, 6 deletions
diff --git a/sources/pyside6/libpyside/feature_select.cpp b/sources/pyside6/libpyside/feature_select.cpp
index c82cccce1..9459e1ca9 100644
--- a/sources/pyside6/libpyside/feature_select.cpp
+++ b/sources/pyside6/libpyside/feature_select.cpp
@@ -499,10 +499,17 @@ static PyObject *methodWithNewName(PyTypeObject *type,
static bool feature_01_addLowerNames(PyTypeObject *type, PyObject *prev_dict, int id)
{
+ PyMethodDef *meth = type->tp_methods;
+ PyObject *lower_dict = type->tp_dict;
+
+ // PYSIDE-1702: A user-defined class in Python has no internal method list.
+ // We are not going to change anything.
+ if (!meth)
+ return PyDict_Update(lower_dict, prev_dict) >= 0;
+
/*
* Add objects with lower names to `type->tp_dict` from 'prev_dict`.
*/
- PyObject *lower_dict = type->tp_dict;
PyObject *key, *value;
Py_ssize_t pos = 0;
@@ -515,11 +522,9 @@ static bool feature_01_addLowerNames(PyTypeObject *type, PyObject *prev_dict, in
continue;
}
}
+
// Then we walk over the tp_methods to get all methods and insert
// them with changed names.
- PyMethodDef *meth = type->tp_methods;
- if (!meth)
- return true;
for (; meth != nullptr && meth->ml_name != nullptr; ++meth) {
const char *name = String::toCString(String::getSnakeCaseName(meth->ml_name, true));
@@ -648,11 +653,18 @@ static bool feature_02_true_property(PyTypeObject *type, PyObject *prev_dict, in
* Use the property info to create true Python property objects.
*/
- // The empty `tp_dict` gets populated by the previous dict.
+ PyMethodDef *meth = type->tp_methods;
PyObject *prop_dict = type->tp_dict;
+
+ // The empty `tp_dict` gets populated by the previous dict.
if (PyDict_Update(prop_dict, prev_dict) < 0)
return false;
+ // PYSIDE-1702: A user-defined class in Python has no internal method list.
+ // We are not going to change anything.
+ if (!meth)
+ return true;
+
// For speed, we establish a helper dict that maps the removed property
// method names to property name.
PyObject *prop_methods = PyDict_GetItem(prop_dict, PyMagicName::property_methods());
diff --git a/sources/pyside6/tests/QtCore/snake_prop_feature_test.py b/sources/pyside6/tests/QtCore/snake_prop_feature_test.py
index 7925c4c0c..18a5e4058 100644
--- a/sources/pyside6/tests/QtCore/snake_prop_feature_test.py
+++ b/sources/pyside6/tests/QtCore/snake_prop_feature_test.py
@@ -67,7 +67,7 @@ class Window(QWidget):
class FeatureTest(unittest.TestCase):
def setUp(self):
qApp or QApplication()
- __feature__.set_selection(0)
+ __feature__.set_selection(0x80) # FIXME: 0 is insecure
def tearDown(self):
__feature__.set_selection(0)
@@ -122,6 +122,34 @@ class FeatureTest(unittest.TestCase):
self.assertEqual(qApp.quit_on_last_window_closed,
QApplication.quit_on_last_window_closed)
+ def testUserClassNotAffected(self):
+ FunctionType = type(lambda: 42)
+ # Note: the types module does not have MethodDescriptorType in low versions.
+ MethodDescriptorType = type(str.split)
+
+ class UserClass(QWidget):
+
+ def someFunc1(self):
+ pass
+
+ @staticmethod
+ def someFunc2(a, b):
+ pass
+
+ inspect = UserClass.__dict__
+ self.assertTrue(isinstance(inspect["someFunc1"], FunctionType))
+ self.assertTrue(isinstance(inspect["someFunc2"], staticmethod))
+ self.assertTrue(isinstance(UserClass.someFunc2, FunctionType))
+ self.assertTrue(isinstance(UserClass.addAction, MethodDescriptorType))
+
+ from __feature__ import snake_case
+
+ inspect = UserClass.__dict__
+ self.assertTrue(isinstance(inspect["someFunc1"], FunctionType))
+ self.assertTrue(isinstance(inspect["someFunc2"], staticmethod))
+ self.assertTrue(isinstance(UserClass.someFunc2, FunctionType))
+ self.assertTrue(isinstance(UserClass.add_action, MethodDescriptorType))
+
if __name__ == '__main__':
unittest.main()
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/feature.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/feature.py
index 8776c7de9..a2b3699cf 100644
--- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/feature.py
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/feature.py
@@ -159,6 +159,7 @@ def __init__():
# Initialize all prior imported modules
for name in sys.modules:
pyside_feature_dict.setdefault(name, -1)
+ _is_initialized = True
def set_selection(select_id, mod_name=None):