diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2020-09-17 07:56:30 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2020-09-17 08:22:55 +0200 |
commit | 4c5e405e691f707f2765b5f920c28213a36d22e5 (patch) | |
tree | 48000f220fc2c4365b276146e3d08a05c3a90312 /sources/pyside2/libpyside | |
parent | 53181fb95d3884cc067d005f37accd92d128bccc (diff) | |
parent | 38814354ff6a30258b79947304fd3a6be4dc7089 (diff) |
Merge remote-tracking branch 'origin/5.15' into dev
Change-Id: I8aa48d07067c45c888c73af87314f6a88c2a6e14
Diffstat (limited to 'sources/pyside2/libpyside')
-rw-r--r-- | sources/pyside2/libpyside/feature_select.cpp | 164 | ||||
-rw-r--r-- | sources/pyside2/libpyside/pyside.cpp | 12 | ||||
-rw-r--r-- | sources/pyside2/libpyside/pysidestaticstrings.cpp | 4 | ||||
-rw-r--r-- | sources/pyside2/libpyside/pysidestaticstrings.h | 4 |
4 files changed, 162 insertions, 22 deletions
diff --git a/sources/pyside2/libpyside/feature_select.cpp b/sources/pyside2/libpyside/feature_select.cpp index d3beeef7a..a1ba76251 100644 --- a/sources/pyside2/libpyside/feature_select.cpp +++ b/sources/pyside2/libpyside/feature_select.cpp @@ -39,6 +39,7 @@ #include "feature_select.h" #include "pyside.h" +#include "pysidestaticstrings.h" #include <shiboken.h> #include <sbkstaticstrings.h> @@ -125,7 +126,7 @@ namespace PySide { namespace Feature { using namespace Shiboken; -typedef bool(*FeatureProc)(PyTypeObject *type, PyObject *prev_dict); +typedef bool(*FeatureProc)(PyTypeObject *type, PyObject *prev_dict, int id); static FeatureProc *featurePointer = nullptr; @@ -226,7 +227,11 @@ static inline void setCurrentSelectId(PyTypeObject *type, int id) static inline PyObject *getCurrentSelectId(PyTypeObject *type) { - return fast_id_array[SbkObjectType_GetReserved(type)]; + int id = SbkObjectType_GetReserved(type); + // This can be too early. + if (id < 0) + id = 0; + return fast_id_array[id]; } static bool replaceClassDict(PyTypeObject *type) @@ -331,7 +336,7 @@ static bool createNewFeatureSet(PyTypeObject *type, PyObject *select_id) // clear the tp_dict that will get new content PyDict_Clear(type->tp_dict); // let the proc re-fill the tp_dict - if (!(*proc)(type, prev_dict)) + if (!(*proc)(type, prev_dict, id)) return false; // if there is still a step, prepare `prev_dict` if (idx >> 1) { @@ -413,18 +418,18 @@ void Select(PyObject *obj) type->tp_dict = SelectFeatureSet(type); } -static bool feature_01_addLowerNames(PyTypeObject *type, PyObject *prev_dict); -static bool feature_02_addDummyNames(PyTypeObject *type, PyObject *prev_dict); -static bool feature_04_addDummyNames(PyTypeObject *type, PyObject *prev_dict); -static bool feature_08_addDummyNames(PyTypeObject *type, PyObject *prev_dict); -static bool feature_10_addDummyNames(PyTypeObject *type, PyObject *prev_dict); -static bool feature_20_addDummyNames(PyTypeObject *type, PyObject *prev_dict); -static bool feature_40_addDummyNames(PyTypeObject *type, PyObject *prev_dict); -static bool feature_80_addDummyNames(PyTypeObject *type, PyObject *prev_dict); +static bool feature_01_addLowerNames(PyTypeObject *type, PyObject *prev_dict, int id); +static bool feature_02_true_property(PyTypeObject *type, PyObject *prev_dict, int id); +static bool feature_04_addDummyNames(PyTypeObject *type, PyObject *prev_dict, int id); +static bool feature_08_addDummyNames(PyTypeObject *type, PyObject *prev_dict, int id); +static bool feature_10_addDummyNames(PyTypeObject *type, PyObject *prev_dict, int id); +static bool feature_20_addDummyNames(PyTypeObject *type, PyObject *prev_dict, int id); +static bool feature_40_addDummyNames(PyTypeObject *type, PyObject *prev_dict, int id); +static bool feature_80_addDummyNames(PyTypeObject *type, PyObject *prev_dict, int id); static FeatureProc featureProcArray[] = { feature_01_addLowerNames, - feature_02_addDummyNames, + feature_02_true_property, feature_04_addDummyNames, feature_08_addDummyNames, feature_10_addDummyNames, @@ -471,8 +476,8 @@ void init() // static PyObject *methodWithNewName(PyTypeObject *type, - PyMethodDef *meth, - const char *new_name) + PyMethodDef *meth, + const char *new_name) { /* * Create a method with a lower case name. @@ -499,7 +504,7 @@ static PyObject *methodWithNewName(PyTypeObject *type, return descr; } -static bool feature_01_addLowerNames(PyTypeObject *type, PyObject *prev_dict) +static bool feature_01_addLowerNames(PyTypeObject *type, PyObject *prev_dict, int id) { /* * Add objects with lower names to `type->tp_dict` from 'prev_dict`. @@ -520,6 +525,9 @@ static bool feature_01_addLowerNames(PyTypeObject *type, PyObject *prev_dict) // 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)); AutoDecRef new_method(methodWithNewName(type, meth, name)); @@ -535,22 +543,140 @@ static bool feature_01_addLowerNames(PyTypeObject *type, PyObject *prev_dict) // // PYSIDE-1019: Support switchable extensions // -// Feature 0x02..0x80: A fake switchable option for testing +// Feature 0x02: Use true properties instead of getters and setters +// + +static PyObject *createProperty(PyObject *getter, PyObject *setter, PyObject *doc) +{ + assert(getter != nullptr); + if (setter == nullptr) + setter = Py_None; + PyObject *deleter = Py_None; + PyObject *prop = PyObject_CallObject(reinterpret_cast<PyObject *>(&PyProperty_Type), nullptr); + AutoDecRef args(Py_BuildValue("OOOO", getter, setter, deleter, doc)); + PyProperty_Type.tp_init(prop, args, nullptr); + return prop; +} + +static PyObject *calcPropDocString(PyTypeObject *type, PyObject *getterName, PyObject *setterName) +{ + // To calculate the docstring, we need the __doc__ attribute of the original + // getter and setter. We temporatily switch back to no features. This + // might change when we have full signature support for features. + auto hold = type->tp_dict; + moveToFeatureSet(type, fast_id_array[0]); + auto dict = type->tp_dict; + auto getter = PyDict_GetItem(dict, getterName); + auto setter = setterName ? PyDict_GetItem(dict, setterName) : nullptr; + PyObject *buf = PyObject_GetAttr(getter, PyMagicName::doc()); + type->tp_dict = hold; + + if (setter == nullptr) + return buf; + AutoDecRef nl(Py_BuildValue("s", "\n")); + AutoDecRef wdoc(PyObject_GetAttr(setter, PyMagicName::doc())); + String::concat(&buf, nl); + String::concat(&buf, wdoc); + return buf; +} + +static QStringList parseFields(const char *propstr) +{ + /* + * Break the string into subfields at ':' and add defaults. + */ + QString s = QString(QLatin1String(propstr)); + auto list = s.split(QLatin1Char(':')); + assert(list.size() == 2 || list.size() == 3); + auto name = list[0]; + auto read = list[1]; + if (read.size() == 0) + list[1] = name; + if (list.size() == 2) + return list; + auto write = list[2]; + if (write.size() == 0) { + list[2] = QLatin1String("set") + name; + list[2][3] = list[2][3].toUpper(); + } + return list; +} + +static PyObject *make_snake_case(QString s, bool lower) +{ + if (s.isNull()) + return nullptr; + return String::getSnakeCaseName(s.toLatin1().data(), lower); +} + +static bool feature_02_true_property(PyTypeObject *type, PyObject *prev_dict, int id) +{ + /* + * Use the property info to create true Python property objects. + */ + + // The empty `tp_dict` gets populated by the previous dict. + PyObject *prop_dict = type->tp_dict; + if (PyDict_Update(prop_dict, prev_dict) < 0) + return false; + + // We then replace methods by properties. + bool lower = (id & 0x01) != 0; + auto props = SbkObjectType_GetPropertyStrings(type); + if (props == nullptr || *props == nullptr) + return true; + for (; *props != nullptr; ++props) { + auto propstr = *props; + auto fields = parseFields(propstr); + bool haveWrite = fields.size() == 3; + PyObject *name = make_snake_case(fields[0], lower); + PyObject *read = make_snake_case(fields[1], lower); + PyObject *write = haveWrite ? make_snake_case(fields[2], lower) : nullptr; + PyObject *getter = PyDict_GetItem(prev_dict, read); + if (getter == nullptr || Py_TYPE(getter) != PepMethodDescr_TypePtr) + continue; + PyObject *setter = haveWrite ? PyDict_GetItem(prev_dict, write) : nullptr; + if (setter != nullptr && Py_TYPE(setter) != PepMethodDescr_TypePtr) + continue; + + PyObject *doc_read = make_snake_case(fields[1], false); + PyObject *doc_write(haveWrite ? make_snake_case(fields[2], false) : nullptr); + AutoDecRef doc(calcPropDocString(type, doc_read, doc_write)); + AutoDecRef PyProperty(createProperty(getter, setter, doc)); + if (PyProperty.isNull()) + return false; + if (PyDict_SetItem(prop_dict, name, PyProperty) < 0) + return false; + if (fields[0] != fields[1] && PyDict_GetItem(prop_dict, read)) + if (PyDict_DelItem(prop_dict, read) < 0) + return false; + // Theoretically, we need to check for multiple signatures to be exact. + // But we don't do so intentionally because it would be confusing. + if (haveWrite && PyDict_GetItem(prop_dict, write)) + if (PyDict_DelItem(prop_dict, write) < 0) + return false; + } + return true; +} + +////////////////////////////////////////////////////////////////////////////// +// +// PYSIDE-1019: Support switchable extensions +// +// Feature 0x04..0x40: A fake switchable option for testing // #define SIMILAR_FEATURE(xx) \ -static bool feature_##xx##_addDummyNames(PyTypeObject *type, PyObject *prev_dict) \ +static bool feature_##xx##_addDummyNames(PyTypeObject *type, PyObject *prev_dict, int id) \ { \ PyObject *dict = type->tp_dict; \ if (PyDict_Update(dict, prev_dict) < 0) \ return false; \ - Py_INCREF(Py_None); \ if (PyDict_SetItemString(dict, "fake_feature_" #xx, Py_None) < 0) \ return false; \ return true; \ } -SIMILAR_FEATURE(02) SIMILAR_FEATURE(04) SIMILAR_FEATURE(08) SIMILAR_FEATURE(10) diff --git a/sources/pyside2/libpyside/pyside.cpp b/sources/pyside2/libpyside/pyside.cpp index 7c8f99b93..2404788d3 100644 --- a/sources/pyside2/libpyside/pyside.cpp +++ b/sources/pyside2/libpyside/pyside.cpp @@ -584,16 +584,22 @@ bool registerInternalQtConf() #ifdef PYSIDE_QT_CONF_PREFIX setupPrefix = QStringLiteral(PYSIDE_QT_CONF_PREFIX); #endif - QString prefixPath = pysideDir.absoluteFilePath(setupPrefix); + const QString prefixPathStr = pysideDir.absoluteFilePath(setupPrefix); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + const QByteArray prefixPath = prefixPathStr.toLocal8Bit(); +#else + // PYSIDE-972, QSettings used by QtCore uses Latin1 + const QByteArray prefixPath = prefixPathStr.toLatin1(); +#endif // rccData needs to be static, otherwise when it goes out of scope, the Qt resource system // will point to invalid memory. - static QByteArray rccData = QByteArray("[Paths]\nPrefix = ") + prefixPath.toLocal8Bit() + static QByteArray rccData = QByteArrayLiteral("[Paths]\nPrefix = ") + prefixPath #ifdef Q_OS_WIN // LibraryExecutables needs to point to Prefix instead of ./bin because we don't // currently conform to the Qt default directory layout on Windows. This is necessary // for QtWebEngineCore to find the location of QtWebEngineProcess.exe. - + QByteArray("\nLibraryExecutables = ") + prefixPath.toLocal8Bit() + + QByteArray("\nLibraryExecutables = ") + prefixPath #endif ; rccData.append('\n'); diff --git a/sources/pyside2/libpyside/pysidestaticstrings.cpp b/sources/pyside2/libpyside/pysidestaticstrings.cpp index 82e233621..760d77632 100644 --- a/sources/pyside2/libpyside/pysidestaticstrings.cpp +++ b/sources/pyside2/libpyside/pysidestaticstrings.cpp @@ -55,5 +55,9 @@ STATIC_STRING_IMPL(qtStaticMetaObject, "staticMetaObject") STATIC_STRING_IMPL(qtConnect, "connect") STATIC_STRING_IMPL(qtDisconnect, "disconnect") STATIC_STRING_IMPL(qtEmit, "emit") +STATIC_STRING_IMPL(dict_ring, "dict_ring") +STATIC_STRING_IMPL(name, "name") +STATIC_STRING_IMPL(property, "property") +STATIC_STRING_IMPL(select_id, "select_id") } // namespace PyName } // namespace PySide diff --git a/sources/pyside2/libpyside/pysidestaticstrings.h b/sources/pyside2/libpyside/pysidestaticstrings.h index 1d5700c51..1222d8f47 100644 --- a/sources/pyside2/libpyside/pysidestaticstrings.h +++ b/sources/pyside2/libpyside/pysidestaticstrings.h @@ -50,6 +50,10 @@ PyObject *qtStaticMetaObject(); PyObject *qtConnect(); PyObject *qtDisconnect(); PyObject *qtEmit(); +PyObject *dict_ring(); +PyObject *name(); +PyObject *property(); +PyObject *select_id(); } // namespace PyName } // namespace PySide |