aboutsummaryrefslogtreecommitdiffstats
path: root/sources
diff options
context:
space:
mode:
authorChristian Tismer <tismer@stackless.com>2022-05-23 12:33:29 +0200
committerChristian Tismer <tismer@stackless.com>2022-06-21 11:06:37 +0200
commit304582e59e63f7620f221d3a9748118479ede099 (patch)
tree52e516c29b8f7eb12036fcc374b90941db9314dd /sources
parent7eb12e4cd3be60b4aaf18530d0c927bef386e913 (diff)
PyEnum: Remove the old duplication of Enums in the enclosing scope
When implementing Python enums, the behavior of old Qt enums was copied: Every enum was also inserted into the enclosing scope. This patch removes that for two reasons: - it is inconsequent to keep an old quirk when we have all enums renewed so much - It is more consistent compared to our competitor - it is a prerequisite to implement efficient lazy initialization PROBLEM: Many constants (about 110) are no longer recognized, for instance `Qt.AlignLeft` should be `Qt.AlignmentFlag.AlignLeft`. The question is if that can be fixed easily in C++, or if the file mapping.py should get ~100 new fixes? SOLUTION: We allow the old enums, but tell nobody that they continue to work. They also are not advertized in the PYI files. [ChangeLog][PySide6] The duplication of enum values into the enclosing scope, allowing to write Qt.AlignLeft instead of Qt.Alignment.AlignLeft, is still implemented but no longer advertized in PYI files or line completion. Task-number: PYSIDE-1735 Change-Id: I79a90d08f2a5a3a069fa551e60d609ecad718239 Pick-to: 6.3 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
Diffstat (limited to 'sources')
-rw-r--r--sources/pyside6/tests/QtCore/qinstallmsghandler_test.py12
-rw-r--r--sources/shiboken6/libshiboken/sbkenum.cpp11
-rw-r--r--sources/shiboken6/libshiboken/sbkfeature_base.cpp52
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/parser.py5
-rw-r--r--sources/shiboken6/tests/samplebinding/derived_test.py3
-rw-r--r--sources/shiboken6/tests/samplebinding/enumfromremovednamespace_test.py2
-rw-r--r--sources/shiboken6/tests/samplebinding/modifications_test.py1
-rw-r--r--sources/shiboken6/tests/samplebinding/sample_test.py3
8 files changed, 70 insertions, 19 deletions
diff --git a/sources/pyside6/tests/QtCore/qinstallmsghandler_test.py b/sources/pyside6/tests/QtCore/qinstallmsghandler_test.py
index 56bec5e65..9c5ae4370 100644
--- a/sources/pyside6/tests/QtCore/qinstallmsghandler_test.py
+++ b/sources/pyside6/tests/QtCore/qinstallmsghandler_test.py
@@ -12,9 +12,9 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
from init_paths import init_test_paths
init_test_paths(False)
-from PySide6.QtCore import (QLibraryInfo, QtCriticalMsg, QtDebugMsg, QtInfoMsg,
+from PySide6.QtCore import (QLibraryInfo, QtMsgType,
QMessageLogContext,
- QtWarningMsg, qCritical, qFormatLogMessage, qDebug,
+ qCritical, qFormatLogMessage, qDebug,
qInstallMessageHandler, qWarning)
@@ -56,18 +56,18 @@ class QInstallMsgHandlerTest(unittest.TestCase):
rethandler = qInstallMessageHandler(handler)
if QLibraryInfo.isDebugBuild():
qDebug("Test Debug")
- self.assertEqual(param[0], QtDebugMsg)
+ self.assertEqual(param[0], QtMsgType.QtDebugMsg)
self.assertEqual(param[2], "Test Debug")
qWarning("Test Warning")
- self.assertEqual(param[0], QtWarningMsg)
+ self.assertEqual(param[0], QtMsgType.QtWarningMsg)
self.assertEqual(param[2], "Test Warning")
qCritical("Test Critical")
- self.assertEqual(param[0], QtCriticalMsg)
+ self.assertEqual(param[0], QtMsgType.QtCriticalMsg)
self.assertEqual(param[2], "Test Critical")
def testFormat(self):
ctx = QMessageLogContext()
- s = qFormatLogMessage(QtInfoMsg, ctx, 'bla')
+ s = qFormatLogMessage(QtMsgType.QtInfoMsg, ctx, 'bla')
self.assertTrue(s)
diff --git a/sources/shiboken6/libshiboken/sbkenum.cpp b/sources/shiboken6/libshiboken/sbkenum.cpp
index b9427142d..3f432dcb2 100644
--- a/sources/shiboken6/libshiboken/sbkenum.cpp
+++ b/sources/shiboken6/libshiboken/sbkenum.cpp
@@ -618,7 +618,7 @@ bool createGlobalEnumItem(PyTypeObject *enumType, PyObject *module, const char *
PyObject *enumItem = createEnumItem(enumType, itemName, itemValue);
if (!enumItem)
return false;
- int ok = PyModule_AddObject(module, itemName, enumItem);
+ int ok = useOldEnum ? PyModule_AddObject(module, itemName, enumItem) : true;
Py_DECREF(enumItem);
return ok >= 0;
}
@@ -629,7 +629,7 @@ bool createScopedEnumItem(PyTypeObject *enumType, PyTypeObject *scope,
PyObject *enumItem = createEnumItem(enumType, itemName, itemValue);
if (!enumItem)
return false;
- int ok = PyDict_SetItemString(scope->tp_dict, itemName, enumItem);
+ int ok = useOldEnum ? PyDict_SetItemString(scope->tp_dict, itemName, enumItem) : true;
Py_DECREF(enumItem);
return ok >= 0;
}
@@ -995,13 +995,6 @@ PyTypeObject *morphLastEnumToPython()
PyObject_SetAttr(obNewType, PyMagicName::qualname(), qual_name);
AutoDecRef module(PyObject_GetAttr(obEnumType, PyMagicName::module()));
PyObject_SetAttr(obNewType, PyMagicName::module(), module);
- // As a last step, fix the item entries in the enclosing object.
- pos = 0;
- while (PyDict_Next(values, &pos, &key, &value)) {
- AutoDecRef entry(PyObject_GetAttr(obNewType, key));
- if (PyObject_SetAttr(lec.scopeOrModule, key, entry) < 0)
- return nullptr;
- }
// Protect against double initialization
setp->replacementType = newType;
#if PY_VERSION_HEX < 0x03080000
diff --git a/sources/shiboken6/libshiboken/sbkfeature_base.cpp b/sources/shiboken6/libshiboken/sbkfeature_base.cpp
index 2b3eba19e..e191204e4 100644
--- a/sources/shiboken6/libshiboken/sbkfeature_base.cpp
+++ b/sources/shiboken6/libshiboken/sbkfeature_base.cpp
@@ -4,6 +4,7 @@
#include "basewrapper.h"
#include "basewrapper_p.h"
#include "autodecref.h"
+#include "sbkenum_p.h"
#include "sbkstring.h"
#include "sbkstaticstrings.h"
#include "sbkstaticstrings_p.h"
@@ -23,8 +24,8 @@ extern "C"
// Maybe the same function from feature_select.cpp will be replaced.
//
-static PyObject *cached_globals = nullptr;
-static PyObject *last_select_id = nullptr;
+static PyObject *cached_globals{};
+static PyObject *last_select_id{};
PyObject *getFeatureSelectId()
{
@@ -86,9 +87,54 @@ PyObject *mangled_type_getattro(PyTypeObject *type, PyObject *name)
* What we change here is the meta class of `QObject`.
*/
static getattrofunc type_getattro = PyType_Type.tp_getattro;
+ static PyObject *ignAttr1 = PyName::qtStaticMetaObject();
+ static PyObject *ignAttr2 = PyMagicName::get();
if (SelectFeatureSet != nullptr)
type->tp_dict = SelectFeatureSet(type);
- return type_getattro(reinterpret_cast<PyObject *>(type), name);
+ auto *ret = type_getattro(reinterpret_cast<PyObject *>(type), name);
+
+ // PYSIDE-1735: Be forgiving with strict enums and fetch the enum, silently.
+ // The PYI files now look correct, but the old duplication is
+ // emulated here. This should be removed in Qt 7, see `parser.py`.
+ //
+ // FIXME PYSIDE7 should remove this forgivingness:
+ //
+ // The duplication of enum values into the enclosing scope, allowing to write
+ // Qt.AlignLeft instead of Qt.Alignment.AlignLeft, is still implemented but
+ // no longer advertized in PYI files or line completion.
+
+ if (!ret && name != ignAttr1 && name != ignAttr2) {
+ PyObject *error_type, *error_value, *error_traceback;
+ PyErr_Fetch(&error_type, &error_value, &error_traceback);
+
+ // This is similar to `find_name_in_mro`, but instead of looking directly into
+ // tp_dict, we search for the attribute in local classes of that dict.
+ PyObject *mro = type->tp_mro;
+ assert(PyTuple_Check(mro));
+ size_t idx, n = PyTuple_GET_SIZE(mro);
+ for (idx = 0; idx < n; ++idx) {
+ // FIXME This loop should further be optimized by installing an extra
+ // <classname>_EnumInfo structure. This comes with the next compatibility patch.
+ auto *base = PyTuple_GET_ITEM(mro, idx);
+ auto *type_base = reinterpret_cast<PyTypeObject *>(base);
+ auto *dict = type_base->tp_dict;
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(dict, &pos, &key, &value)) {
+ static auto *EnumMeta = getPyEnumMeta();
+ if (Py_TYPE(value) == EnumMeta) {
+ auto *valtype = reinterpret_cast<PyTypeObject *>(value);
+ auto *result = PyDict_GetItem(valtype->tp_dict, name);
+ if (result) {
+ Py_INCREF(result);
+ return result;
+ }
+ }
+ }
+ }
+ PyErr_Restore(error_type, error_value, error_traceback);
+ }
+ return ret;
}
PyObject *Sbk_TypeGet___dict__(PyTypeObject *type, void *context)
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/parser.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/parser.py
index 5dabc395f..4c8ade025 100644
--- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/parser.py
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/parser.py
@@ -62,7 +62,6 @@ def _get_flag_enum_option():
flag = bool(int(opt))
elif hasattr(sys, sysname):
flag = bool(getattr(sys, sysname))
- sysver = sys.version_info[:2]
# PYSIDE-1797: Emit a warning when we may remove pep384_issue33738.cpp
if pyminver and pyminver >= (3, 8):
warnings.warn(f"\n *** Python is at version {'.'.join(map(str, pyminver))} now. "
@@ -71,6 +70,10 @@ def _get_flag_enum_option():
if pymaxver and pymaxver > (3, 10):
warnings.warn(f"\n *** Python is at version {'.'.join(map(str, pymaxver))} now. "
f"Please check if enum_310.py should be updated! ***")
+ # PYSIDE-1735: Emit a warning when we may update enum_310.py
+ if ver[:2] >= (7, 0):
+ warnings.warn(f"\n *** PySide is at version {'.'.join(map(str, ver[:2]))} now. "
+ f"Please drop the forgiving Enum behavior in `mangled_type_getattro` ***")
# modify the sys attribute to bool
setattr(sys, sysname, flag)
# modify the env attribute to "0" or "1"
diff --git a/sources/shiboken6/tests/samplebinding/derived_test.py b/sources/shiboken6/tests/samplebinding/derived_test.py
index 897b1654e..2d5eb4293 100644
--- a/sources/shiboken6/tests/samplebinding/derived_test.py
+++ b/sources/shiboken6/tests/samplebinding/derived_test.py
@@ -40,6 +40,7 @@ class DerivedTest(unittest.TestCase):
'id_', 'pureVirtual', 'unpureVirtual'])
self.assertTrue(inherited_methods.issubset(dir(Derived)))
+ @unittest.skipIf(sys.pyside63_option_python_enum, "Makes no sense with strict Enums")
def testOverloadedMethodCall(self):
'''Test if the correct overloaded method is being called.'''
derived = Derived()
@@ -56,6 +57,7 @@ class DerivedTest(unittest.TestCase):
self.assertEqual(type(result), OverloadedFuncEnum)
self.assertEqual(result, sample.OverloadedFunc_d)
+ @unittest.skipIf(sys.pyside63_option_python_enum, "Makes no sense with strict Enums")
def testOtherOverloadedMethodCall(self):
'''Another test to check overloaded method calling, just to double check.'''
derived = Derived()
@@ -68,6 +70,7 @@ class DerivedTest(unittest.TestCase):
self.assertEqual(type(result), Derived.OtherOverloadedFuncEnum)
self.assertEqual(result, Derived.OtherOverloadedFunc_id)
+ @unittest.skipIf(sys.pyside63_option_python_enum, "Makes no sense with strict Enums")
def testOverloadedMethodCallWithDifferentNumericTypes(self):
'''Test if the correct overloaded method accepts a different numeric type as argument.'''
derived = Derived()
diff --git a/sources/shiboken6/tests/samplebinding/enumfromremovednamespace_test.py b/sources/shiboken6/tests/samplebinding/enumfromremovednamespace_test.py
index 8cf21d4ff..f70621c59 100644
--- a/sources/shiboken6/tests/samplebinding/enumfromremovednamespace_test.py
+++ b/sources/shiboken6/tests/samplebinding/enumfromremovednamespace_test.py
@@ -21,6 +21,8 @@ from shibokensupport.signature import get_signature
class TestEnumFromRemovedNamespace(unittest.TestCase):
+
+ @unittest.skipIf(sys.pyside63_option_python_enum, "Makes no sense with strict Enums")
def testEnumPromotedToGlobal(self):
sample.RemovedNamespace1_Enum
self.assertEqual(sample.RemovedNamespace1_Enum_Value0, 0)
diff --git a/sources/shiboken6/tests/samplebinding/modifications_test.py b/sources/shiboken6/tests/samplebinding/modifications_test.py
index 478e0700d..d1e70004f 100644
--- a/sources/shiboken6/tests/samplebinding/modifications_test.py
+++ b/sources/shiboken6/tests/samplebinding/modifications_test.py
@@ -41,6 +41,7 @@ class ModificationsTest(unittest.TestCase):
# PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
gc.collect()
+ @unittest.skipIf(sys.pyside63_option_python_enum, "Makes no sense with strict Enums")
def testClassMembersAvailability(self):
'''Test if Modified class really have the expected members.'''
expected_members = set(['OverloadedModFunc', 'OverloadedNone',
diff --git a/sources/shiboken6/tests/samplebinding/sample_test.py b/sources/shiboken6/tests/samplebinding/sample_test.py
index 35595649d..52abc968f 100644
--- a/sources/shiboken6/tests/samplebinding/sample_test.py
+++ b/sources/shiboken6/tests/samplebinding/sample_test.py
@@ -18,6 +18,7 @@ import sample
class ModuleTest(unittest.TestCase):
'''Test case for module and global functions'''
+ @unittest.skipIf(sys.pyside63_option_python_enum, "Makes no sense with strict Enums")
def testModuleMembers(self):
'''Test availability of classes, global functions and other members on binding'''
expected_members = set(['Abstract', 'Derived', 'Point',
@@ -30,12 +31,14 @@ class ModuleTest(unittest.TestCase):
'GlobalEnum', 'NoThing'])
self.assertTrue(expected_members.issubset(dir(sample)))
+ @unittest.skipIf(sys.pyside63_option_python_enum, "Makes no sense with strict Enums")
def testAbstractPrintFormatEnum(self):
'''Test availability of PrintFormat enum from Abstract class'''
enum_members = set(['PrintFormat', 'Short', 'Verbose',
'OnlyId', 'ClassNameAndId'])
self.assertTrue(enum_members.issubset(dir(sample.Abstract)))
+ @unittest.skipIf(sys.pyside63_option_python_enum, "Makes no sense with strict Enums")
def testSampleNamespaceOptionEnum(self):
'''Test availability of Option enum from SampleNamespace namespace'''
enum_members = set(['Option', 'None_', 'RandomNumber', 'UnixTime'])