aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2020-08-17 07:41:37 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2020-08-17 07:41:37 +0200
commitf440ebfd838d0b754bbba38fbbd2ccf5318f7347 (patch)
tree53d1431ceb7d64826a86f812c4b9a4fe3310f846
parent7a1fe1519159a8bcaa61aec35c1d942ed024bf73 (diff)
parent58a0d36d9271e91bd21272a9fe3b736dd90db58d (diff)
Merge remote-tracking branch 'origin/5.15' into dev
-rw-r--r--sources/pyside2/PySide2/QtCore/typesystem_core_common.xml4
-rw-r--r--sources/pyside2/PySide2/__init__.py.in16
-rw-r--r--sources/pyside2/PySide2/glue/qtcore.cpp4
-rw-r--r--sources/pyside2/libpyside/feature_select.cpp136
-rw-r--r--sources/pyside2/libpyside/pyside.cpp2
-rw-r--r--sources/pyside2/tests/QtCore/multiple_feature_test.py9
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.cpp1
-rw-r--r--sources/shiboken2/libshiboken/basewrapper.cpp29
-rw-r--r--sources/shiboken2/libshiboken/basewrapper.h4
-rw-r--r--sources/shiboken2/libshiboken/basewrapper_p.h10
-rw-r--r--sources/shiboken2/libshiboken/bindingmanager.cpp10
-rw-r--r--sources/shiboken2/libshiboken/signature.cpp49
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__feature__.py108
13 files changed, 287 insertions, 95 deletions
diff --git a/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml b/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml
index 982674500..d43c5a29b 100644
--- a/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml
+++ b/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml
@@ -647,6 +647,10 @@
<inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qt-qflag"/>
</add-function>
+ <add-function signature="__init_feature__()">
+ <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qt-init-feature"/>
+ </add-function>
+
<add-function signature="qAbs(double)" return-type="double">
<inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qt-qabs"/>
</add-function>
diff --git a/sources/pyside2/PySide2/__init__.py.in b/sources/pyside2/PySide2/__init__.py.in
index f860c6ac9..5c33c57a0 100644
--- a/sources/pyside2/PySide2/__init__.py.in
+++ b/sources/pyside2/PySide2/__init__.py.in
@@ -1,6 +1,7 @@
from __future__ import print_function
import os
import sys
+from textwrap import dedent
__all__ = list("Qt" + body for body in
"@all_module_shortnames@"
@@ -62,7 +63,20 @@ def _setupQtDirectories():
raise
# Trigger signature initialization.
- type.__signature__
+ try:
+ type.__signature__
+ except AttributeError:
+ print(dedent('''\
+ {stars}
+ PySide2/__init__.py: The `signature` module was not initialized.
+ This libshiboken module was loaded from
+
+ "{shiboken2.__file__}".
+
+ Please make sure that this is the real shiboken2 binary and not just a folder.
+ {stars}
+ ''').format(stars=79*"*", **locals()), file=sys.stderr)
+ raise
if sys.platform == 'win32':
# PATH has to contain the package directory, otherwise plugins
diff --git a/sources/pyside2/PySide2/glue/qtcore.cpp b/sources/pyside2/PySide2/glue/qtcore.cpp
index 6d8c0876d..092bfab80 100644
--- a/sources/pyside2/PySide2/glue/qtcore.cpp
+++ b/sources/pyside2/PySide2/glue/qtcore.cpp
@@ -595,6 +595,10 @@ PySide::runCleanupFunctions();
%PYARG_0 = PySide::QEnum::QEnumMacro(%1, true);
// @snippet qt-qflag
+// @snippet qt-init-feature
+PySide::Feature::init();
+// @snippet qt-init-feature
+
// @snippet qt-pysideinit
Shiboken::Conversions::registerConverterName(SbkPySide2_QtCoreTypeConverters[SBK_QSTRING_IDX], "unicode");
Shiboken::Conversions::registerConverterName(SbkPySide2_QtCoreTypeConverters[SBK_QSTRING_IDX], "str");
diff --git a/sources/pyside2/libpyside/feature_select.cpp b/sources/pyside2/libpyside/feature_select.cpp
index 7b98b03f0..d3beeef7a 100644
--- a/sources/pyside2/libpyside/feature_select.cpp
+++ b/sources/pyside2/libpyside/feature_select.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "feature_select.h"
+#include "pyside.h"
#include <shiboken.h>
#include <sbkstaticstrings.h>
@@ -51,7 +52,7 @@
// This functionality is no longer implemented in the signature module, since
// the PyCFunction getsets do not have to be modified any longer.
// Instead, we simply exchange the complete class dicts. This is done in the
-// basewrapper.cpp file.
+// basewrapper.cpp file and in every generated `tp_(get|set)attro`.
//
// This is the general framework of the switchable extensions.
// A maximum of eight features is planned so far. This seems to be enough.
@@ -65,10 +66,10 @@
-------------------------------------
The basic idea is to replace the `tp_dict` of a QObject derived type.
-This way, we can replace the methods of the dict in no time.
+This way, we can replace the methods of the class in no time.
The crucial point to understand is how the `tp_dict` is actually accessed:
-When you type "QObject.__dict__", the descriptor of SbkObjectType_Type
+When you type "QObject.__dict__", the descriptor of `SbkObjectType_Type`
is called. This descriptor is per default unassigned, so the base class
PyType_Type provides the tp_getset method `type_dict`:
@@ -111,9 +112,9 @@ looks into the `__name__` attribute of the active module and decides which
version of `tp_dict` is needed. Then the right dict is searched in the ring
and created if not already there.
-Furthermore, we need to overwrite every `tp_getattro` and `tp_setattro`
-with a version that switches dicts before looking up methods.
-The dict changing must follow the `tp_mro` in order to change all names.
+Furthermore, we need to overwrite every `tp_(get|set)attro` with a version
+that switches dicts right before looking up methods.
+The dict changing must walk the whole `tp_mro` in order to change all names.
This is everything that the following code does.
@@ -124,21 +125,41 @@ namespace PySide { namespace Feature {
using namespace Shiboken;
-static PyObject *getFeatureSelectID()
+typedef bool(*FeatureProc)(PyTypeObject *type, PyObject *prev_dict);
+
+static FeatureProc *featurePointer = nullptr;
+
+static PyObject *cached_globals = nullptr;
+static PyObject *last_select_id = nullptr;
+
+static PyObject *_fast_id_array[1 + 256] = {};
+// this will point to element 1 to allow indexing from -1
+static PyObject **fast_id_array;
+
+static inline PyObject *getFeatureSelectId()
{
- static PyObject *zero = PyInt_FromLong(0);
+ static PyObject *undef = fast_id_array[-1];
static PyObject *feature_dict = GetFeatureDict();
// these things are all borrowed
PyObject *globals = PyEval_GetGlobals();
- if (globals == nullptr)
- return zero;
+ if ( globals == nullptr
+ || globals == cached_globals)
+ return last_select_id;
+
PyObject *modname = PyDict_GetItem(globals, PyMagicName::name());
if (modname == nullptr)
- return zero;
- PyObject *flag = PyDict_GetItem(feature_dict, modname);
- if (flag == nullptr || !PyInt_Check(flag)) // int/long cheating
- return zero;
- return flag;
+ return last_select_id;
+
+ PyObject *select_id = PyDict_GetItem(feature_dict, modname);
+ if ( select_id == nullptr
+ || !PyInt_Check(select_id) // int/long cheating
+ || select_id == undef)
+ return last_select_id;
+
+ cached_globals = globals;
+ last_select_id = select_id;
+ assert(PyInt_AsSsize_t(select_id) >= 0);
+ return select_id;
}
// Create a derived dict class
@@ -193,6 +214,21 @@ static inline PyObject *getSelectId(PyObject *dict)
return select_id;
}
+static inline void setCurrentSelectId(PyTypeObject *type, PyObject *select_id)
+{
+ SbkObjectType_SetReserved(type, PyInt_AsSsize_t(select_id)); // int/long cheating
+}
+
+static inline void setCurrentSelectId(PyTypeObject *type, int id)
+{
+ SbkObjectType_SetReserved(type, id);
+}
+
+static inline PyObject *getCurrentSelectId(PyTypeObject *type)
+{
+ return fast_id_array[SbkObjectType_GetReserved(type)];
+}
+
static bool replaceClassDict(PyTypeObject *type)
{
/*
@@ -251,6 +287,7 @@ static bool moveToFeatureSet(PyTypeObject *type, PyObject *select_id)
// This works because small numbers are singleton objects.
if (current_id == select_id) {
type->tp_dict = dict;
+ setCurrentSelectId(type, select_id);
return true;
}
} while (dict != initial_dict);
@@ -258,10 +295,6 @@ static bool moveToFeatureSet(PyTypeObject *type, PyObject *select_id)
return false;
}
-typedef bool(*FeatureProc)(PyTypeObject *type, PyObject *prev_dict);
-
-static FeatureProc *featurePointer = nullptr;
-
static bool createNewFeatureSet(PyTypeObject *type, PyObject *select_id)
{
/*
@@ -279,18 +312,19 @@ static bool createNewFeatureSet(PyTypeObject *type, PyObject *select_id)
// make sure that small integers are cached
assert(small_1 != nullptr && small_1 == small_2);
- static auto zero = PyInt_FromLong(0);
+ static auto zero = fast_id_array[0];
bool ok = moveToFeatureSet(type, zero);
Q_UNUSED(ok);
assert(ok);
AutoDecRef prev_dict(type->tp_dict);
- Py_INCREF(prev_dict);
+ Py_INCREF(prev_dict); // keep the first ref unchanged
if (!addNewDict(type, select_id))
return false;
- auto id = PyInt_AsSsize_t(select_id);
+ auto id = PyInt_AsSsize_t(select_id); // int/long cheating
if (id == -1)
return false;
+ setCurrentSelectId(type, id);
FeatureProc *proc = featurePointer;
for (int idx = id; *proc != nullptr; ++proc, idx >>= 1) {
if (idx & 1) {
@@ -312,8 +346,12 @@ static bool createNewFeatureSet(PyTypeObject *type, PyObject *select_id)
static bool SelectFeatureSetSubtype(PyTypeObject *type, PyObject *select_id)
{
+ /*
+ * This is the selector for one sublass. We need to call this for
+ * every subclass until no more subclasses or reaching the wanted id.
+ */
if (Py_TYPE(type->tp_dict) == Py_TYPE(PyType_Type.tp_dict)) {
- // PYSIDE-1019: On first touch, we initialize the dynamic naming.
+ // On first touch, we initialize the dynamic naming.
// The dict type will be replaced after the first call.
if (!replaceClassDict(type)) {
Py_FatalError("failed to replace class dict!");
@@ -329,21 +367,29 @@ static bool SelectFeatureSetSubtype(PyTypeObject *type, PyObject *select_id)
return true;
}
-static PyObject *SelectFeatureSet(PyTypeObject *type)
+static inline PyObject *SelectFeatureSet(PyTypeObject *type)
{
/*
- * This is the main function of the module.
- * Generated functions call this directly.
- * Shiboken will assign it via a public hook of `basewrapper.cpp`.
+ * This is the main function of the module.
+ * The purpose of this function is to switch the dict of a class right
+ * before a (get|set)attro call is performed.
+ *
+ * Generated functions call this directly.
+ * Shiboken will assign it via a public hook of `basewrapper.cpp`.
*/
if (Py_TYPE(type->tp_dict) == Py_TYPE(PyType_Type.tp_dict)) {
- // PYSIDE-1019: On first touch, we initialize the dynamic naming.
- // The dict type will be replaced after the first call.
+ // We initialize the dynamic features by using our own dict type.
if (!replaceClassDict(type))
return nullptr;
}
- PyObject *select_id = getFeatureSelectID(); // borrowed
- AutoDecRef current_id(getSelectId(type->tp_dict));
+ PyObject *select_id = getFeatureSelectId(); // borrowed
+ PyObject *current_id = getCurrentSelectId(type); // borrowed
+ static PyObject *undef = fast_id_array[-1];
+
+ // PYSIDE-1019: During import PepType_SOTP is still zero.
+ if (current_id == undef)
+ current_id = select_id = fast_id_array[0];
+
if (select_id != current_id) {
PyObject *mro = type->tp_mro;
Py_ssize_t idx, n = PyTuple_GET_SIZE(mro);
@@ -361,6 +407,8 @@ static PyObject *SelectFeatureSet(PyTypeObject *type)
// For cppgenerator:
void Select(PyObject *obj)
{
+ if (featurePointer == nullptr)
+ return;
auto type = Py_TYPE(obj);
type->tp_dict = SelectFeatureSet(type);
}
@@ -386,10 +434,28 @@ static FeatureProc featureProcArray[] = {
nullptr
};
+void finalize()
+{
+ for (int idx = -1; idx < 256; ++idx)
+ Py_DECREF(fast_id_array[idx]);
+}
+
void init()
{
- featurePointer = featureProcArray;
- initSelectableFeature(SelectFeatureSet);
+ // This function can be called multiple times.
+ static bool is_initialized = false;
+ if (!is_initialized) {
+ fast_id_array = &_fast_id_array[1];
+ for (int idx = -1; idx < 256; ++idx)
+ fast_id_array[idx] = PyInt_FromLong(idx);
+ last_select_id = fast_id_array[0];
+ featurePointer = featureProcArray;
+ initSelectableFeature(SelectFeatureSet);
+ registerCleanupFunction(finalize);
+ is_initialized = true;
+ }
+ // Reset the cache. This is called at any "from __feature__ import".
+ cached_globals = nullptr;
}
//////////////////////////////////////////////////////////////////////////////
@@ -404,7 +470,7 @@ void init()
// basewrapper.cpp file.
//
-static PyObject *methodWithLowerName(PyTypeObject *type,
+static PyObject *methodWithNewName(PyTypeObject *type,
PyMethodDef *meth,
const char *new_name)
{
@@ -456,7 +522,7 @@ static bool feature_01_addLowerNames(PyTypeObject *type, PyObject *prev_dict)
PyMethodDef *meth = type->tp_methods;
for (; meth != nullptr && meth->ml_name != nullptr; ++meth) {
const char *name = String::toCString(String::getSnakeCaseName(meth->ml_name, true));
- AutoDecRef new_method(methodWithLowerName(type, meth, name));
+ AutoDecRef new_method(methodWithNewName(type, meth, name));
if (new_method.isNull())
return false;
if (PyDict_SetItemString(lower_dict, name, new_method) < 0)
diff --git a/sources/pyside2/libpyside/pyside.cpp b/sources/pyside2/libpyside/pyside.cpp
index c1ddfc278..66e931164 100644
--- a/sources/pyside2/libpyside/pyside.cpp
+++ b/sources/pyside2/libpyside/pyside.cpp
@@ -50,7 +50,6 @@
#include "pysidemetafunction_p.h"
#include "pysidemetafunction.h"
#include "dynamicqmetaobject.h"
-#include "feature_select.h"
#include <autodecref.h>
#include <basewrapper.h>
@@ -94,7 +93,6 @@ void init(PyObject *module)
MetaFunction::init(module);
// Init signal manager, so it will register some meta types used by QVariant.
SignalManager::instance();
- Feature::init();
initQApp();
}
diff --git a/sources/pyside2/tests/QtCore/multiple_feature_test.py b/sources/pyside2/tests/QtCore/multiple_feature_test.py
index 26488326c..351090382 100644
--- a/sources/pyside2/tests/QtCore/multiple_feature_test.py
+++ b/sources/pyside2/tests/QtCore/multiple_feature_test.py
@@ -48,7 +48,8 @@ from init_paths import init_test_paths
init_test_paths(False)
from PySide2 import QtCore
-from PySide2.support.__feature__ import _really_all_feature_names
+from PySide2.support.__feature__ import (
+ _really_all_feature_names, pyside_feature_dict)
from textwrap import dedent
"""
@@ -67,7 +68,6 @@ class FeaturesTest(unittest.TestCase):
"""
Test for all 256 possible combinations of `__feature__` imports.
"""
- global __name__
def tst_bit0(flag, self):
if flag == 0:
@@ -108,9 +108,10 @@ class FeaturesTest(unittest.TestCase):
tst_bit4, tst_bit5, tst_bit6, tst_bit7]
for idx in range(0x100):
- __name__ = "feature_{:02x}".format(idx)
+ pyside_feature_dict.clear()
+ config = "feature_{:02x}".format(idx)
print()
- print("--- Feature Test Module `{}` ---".format(__name__))
+ print("--- Feature Test Config `{}` ---".format(config))
print("Imports:")
for bit in range(8):
if idx & 1 << bit:
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
index b10074f79..9182b76e2 100644
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
@@ -5690,6 +5690,7 @@ bool CppGenerator::finishGeneration()
s << includeQDebug;
s << "#include <pyside.h>\n";
s << "#include <pysideqenum.h>\n";
+ s << "#include <feature_select.h>\n";
s << "#include <qapp_macro.h>\n";
}
diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp
index a602688ec..c3c16cb02 100644
--- a/sources/shiboken2/libshiboken/basewrapper.cpp
+++ b/sources/shiboken2/libshiboken/basewrapper.cpp
@@ -515,11 +515,13 @@ void SbkObjectTypeDealloc(PyObject *pyObj)
// PYSIDE-1019: Support switchable extensions
//
// We simply exchange the complete class dicts.
-// This is done in
-// - mangled_type_getattro which replaces
-// - Sbk_TypeGet___dict__
-// - SbkObjectType_replace_getattro
-// - SbkObjectType_replace_setattro
+//
+// This is done in which replaces
+// --------------- --------------
+// mangled_type_getattro type_getattro
+// Sbk_TypeGet___dict__ type_dict
+// SbkObject_GenericGetAttr PyObject_GenericGetAttr
+// SbkObject_GenericSetAttr PyObject_GenericSetAttr
//
void initSelectableFeature(SelectableFeatureHook func)
@@ -555,7 +557,7 @@ static PyObject *Sbk_TypeGet___dict__(PyTypeObject *type, void *context)
// These functions replace the standard PyObject_Generic(Get|Set)Attr functions.
// They provide the default that "object" inherits.
-// Everything else is directly handled by an insertion PyObject_GenericGetAttr
+// Everything else is directly handled by cppgenerator that calls `Feature::Select`.
static PyObject *SbkObject_GenericGetAttr(PyObject *obj, PyObject *name)
{
auto type = Py_TYPE(obj);
@@ -572,6 +574,21 @@ static int SbkObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *val
return PyObject_GenericSetAttr(obj, name, value);
}
+// Caching the select Id.
+int SbkObjectType_GetReserved(PyTypeObject *type)
+{
+ auto ptr = PepType_SOTP(reinterpret_cast<SbkObjectType *>(type));
+ // PYSIDE-1019: During import PepType_SOTP is still zero.
+ if (ptr == nullptr)
+ return -1;
+ return ptr->pyside_reserved_bits;
+}
+
+void SbkObjectType_SetReserved(PyTypeObject *type, int value)
+{
+ PepType_SOTP(reinterpret_cast<SbkObjectType *>(type))->pyside_reserved_bits = value;
+}
+
//
//////////////////////////////////////////////////////////////////////////////
diff --git a/sources/shiboken2/libshiboken/basewrapper.h b/sources/shiboken2/libshiboken/basewrapper.h
index 47ea89577..b233c02b4 100644
--- a/sources/shiboken2/libshiboken/basewrapper.h
+++ b/sources/shiboken2/libshiboken/basewrapper.h
@@ -100,6 +100,10 @@ LIBSHIBOKEN_API void initSelectableFeature(SelectableFeatureHook func);
// PYSIDE-1019: Publish the start of setattro.
LIBSHIBOKEN_API void SbkObject_NotifySetAttr(PyObject *obj, PyObject *name, PyObject *value);
+// PYSIDE-1019: Get access to PySide reserved bits.
+LIBSHIBOKEN_API int SbkObjectType_GetReserved(PyTypeObject *type);
+LIBSHIBOKEN_API void SbkObjectType_SetReserved(PyTypeObject *type, int value);
+
extern LIBSHIBOKEN_API PyTypeObject *SbkObjectType_TypeF(void);
extern LIBSHIBOKEN_API SbkObjectType *SbkObject_TypeF(void);
diff --git a/sources/shiboken2/libshiboken/basewrapper_p.h b/sources/shiboken2/libshiboken/basewrapper_p.h
index 56a647b21..482a3ea2a 100644
--- a/sources/shiboken2/libshiboken/basewrapper_p.h
+++ b/sources/shiboken2/libshiboken/basewrapper_p.h
@@ -130,14 +130,16 @@ struct SbkObjectTypePrivate
TypeDiscoveryFuncV2 type_discovery;
/// Pointer to a function responsible for deletion of the C++ instance calling the proper destructor.
ObjectDestructor cpp_dtor;
+ /// PYSIDE-1019: Caching the current select Id
+ unsigned int pyside_reserved_bits : 8; // MSVC has bug with the sign bit!
/// True if this type holds two or more C++ instances, e.g.: a Python class which inherits from two C++ classes.
- int is_multicpp : 1;
+ unsigned int is_multicpp : 1;
/// True if this type was defined by the user.
- int is_user_type : 1;
+ unsigned int is_user_type : 1;
/// Tells is the type is a value type or an object-type, see BEHAVIOUR_ *constants.
// TODO-CONVERTERS: to be deprecated/removed
- int type_behaviour : 2;
- int delete_in_main_thread : 1;
+ unsigned int type_behaviour : 2;
+ unsigned int delete_in_main_thread : 1;
/// C++ name
char *original_name;
/// Type user data
diff --git a/sources/shiboken2/libshiboken/bindingmanager.cpp b/sources/shiboken2/libshiboken/bindingmanager.cpp
index b35a02ef4..4f8c6068a 100644
--- a/sources/shiboken2/libshiboken/bindingmanager.cpp
+++ b/sources/shiboken2/libshiboken/bindingmanager.cpp
@@ -274,16 +274,10 @@ SbkObject *BindingManager::retrieveWrapper(const void *cptr)
return iter->second;
}
-static bool mangleNameFlag(PyTypeObject *type)
+static inline bool mangleNameFlag(PyTypeObject *type)
{
// PYSIDE-1019: See if a dict is set with a snake_case bit.
- static PyTypeObject *old_dict_type = Py_TYPE(PyType_Type.tp_dict);
- auto dict = type->tp_dict;
- if (Py_TYPE(dict) == old_dict_type)
- return false;
- Shiboken::AutoDecRef select_id(PyObject_GetAttr(dict, Shiboken::PyName::select_id()));
- auto id = PyInt_AsSsize_t(select_id);
- return (id & 1) != 0;
+ return (SbkObjectType_GetReserved(type) & 1) != 0;
}
PyObject *BindingManager::getOverride(const void *cptr, PyObject *methodNameCache[2], const char *methodName)
diff --git a/sources/shiboken2/libshiboken/signature.cpp b/sources/shiboken2/libshiboken/signature.cpp
index 4614a131e..e4dc27ea7 100644
--- a/sources/shiboken2/libshiboken/signature.cpp
+++ b/sources/shiboken2/libshiboken/signature.cpp
@@ -653,17 +653,22 @@ _fixup_getset(PyTypeObject *type, const char *name, PyGetSetDef *new_gsp)
}
}
}
- // staticmethod has just a __doc__ in the class
- assert(strcmp(type->tp_name, "staticmethod") == 0);
+ PyMemberDef *md = type->tp_members;
+ if (md != nullptr)
+ for (; md->name != nullptr; md++)
+ if (strcmp(md->name, name) == 0)
+ return 1;
+ // staticmethod has just a `__doc__` in the class
+ assert(strcmp(type->tp_name, "staticmethod") == 0 && strcmp(name, "__doc__") == 0);
return 0;
}
static int
-add_more_getsets(PyTypeObject *type, PyGetSetDef *gsp, PyObject **old_descr)
+add_more_getsets(PyTypeObject *type, PyGetSetDef *gsp, PyObject **doc_descr)
{
/*
- * This function is used to assign a new __signature__ attribute,
- * and also to override a __doc__ attribute.
+ * This function is used to assign a new `__signature__` attribute,
+ * and also to override a `__doc__` or `__name__` attribute.
*/
assert(PyType_Check(type));
PyType_Ready(type);
@@ -671,9 +676,11 @@ add_more_getsets(PyTypeObject *type, PyGetSetDef *gsp, PyObject **old_descr)
for (; gsp->name != nullptr; gsp++) {
PyObject *have_descr = PyDict_GetItemString(dict, gsp->name);
if (have_descr != nullptr) {
- assert(strcmp(gsp->name, "__doc__") == 0);
Py_INCREF(have_descr);
- *old_descr = have_descr;
+ if (strcmp(gsp->name, "__doc__") == 0)
+ *doc_descr = have_descr;
+ else
+ assert(false);
if (!_fixup_getset(type, gsp->name, gsp))
continue;
}
@@ -824,7 +831,7 @@ static PyGetSetDef new_PyWrapperDescr_getsets[] = {
//
// Additionally to the interface via __signature__, we also provide
// a general function, which allows for different signature layouts.
-// The "modifier" argument is a string that is passed in from loader.py .
+// The "modifier" argument is a string that is passed in from 'loader.py'.
// Configuration what the modifiers mean is completely in Python.
//
@@ -909,13 +916,25 @@ PySide_PatchTypes(void)
reinterpret_cast<PyObject *>(&PyString_Type), "split"));
Shiboken::AutoDecRef wrap_descr(PyObject_GetAttrString(
reinterpret_cast<PyObject *>(Py_TYPE(Py_True)), "__add__"));
+ // abbreviations for readability
+ auto md_gs = new_PyMethodDescr_getsets;
+ auto md_doc = &old_md_doc_descr;
+ auto cf_gs = new_PyCFunction_getsets;
+ auto cf_doc = &old_cf_doc_descr;
+ auto sm_gs = new_PyStaticMethod_getsets;
+ auto sm_doc = &old_sm_doc_descr;
+ auto tp_gs = new_PyType_getsets;
+ auto tp_doc = &old_tp_doc_descr;
+ auto wd_gs = new_PyWrapperDescr_getsets;
+ auto wd_doc = &old_wd_doc_descr;
+
if (meth_descr.isNull() || wrap_descr.isNull()
|| PyType_Ready(Py_TYPE(meth_descr)) < 0
- || add_more_getsets(PepMethodDescr_TypePtr, new_PyMethodDescr_getsets, &old_md_doc_descr) < 0
- || add_more_getsets(&PyCFunction_Type, new_PyCFunction_getsets, &old_cf_doc_descr) < 0
- || add_more_getsets(PepStaticMethod_TypePtr, new_PyStaticMethod_getsets, &old_sm_doc_descr) < 0
- || add_more_getsets(&PyType_Type, new_PyType_getsets, &old_tp_doc_descr) < 0
- || add_more_getsets(Py_TYPE(wrap_descr), new_PyWrapperDescr_getsets, &old_wd_doc_descr) < 0
+ || add_more_getsets(PepMethodDescr_TypePtr, md_gs, md_doc) < 0
+ || add_more_getsets(&PyCFunction_Type, cf_gs, cf_doc) < 0
+ || add_more_getsets(PepStaticMethod_TypePtr, sm_gs, sm_doc) < 0
+ || add_more_getsets(&PyType_Type, tp_gs, tp_doc) < 0
+ || add_more_getsets(Py_TYPE(wrap_descr), wd_gs, wd_doc) < 0
)
return -1;
#ifndef _WIN32
@@ -1214,8 +1233,8 @@ FinishSignatureInitialization(PyObject *module, const char *signatures[])
* Still, it is not possible to call init phase 2 from here,
* because the import is still running. Do it from Python!
*/
- PySide_PatchTypes();
- if (PySide_FinishSignatures(module, signatures) < 0) {
+ if ( PySide_PatchTypes() < 0
+ || PySide_FinishSignatures(module, signatures) < 0) {
PyErr_Print();
PyErr_SetNone(PyExc_ImportError);
}
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__feature__.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__feature__.py
index d088ea41b..57b9eee15 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__feature__.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__feature__.py
@@ -44,31 +44,41 @@ __feature__.py
This is the feature file for the Qt for Python project. There is some
similarity to Python's `__future__` file, but also some distinction.
+
+The normal usage is like
+
+ from __feature__ import <feature_name> [, ...]
+ ...
+
+Alternatively, there is the `set_selection` function which uses select_id's
+and takes an optional `mod_name` parameter.
+
+The select id `-1` has the spectial meaning "ignore this module".
"""
import sys
all_feature_names = [
"snake_case",
- "_dummy_feature_02",
- "_dummy_feature_04",
- "_dummy_feature_08",
- "_dummy_feature_10",
- "_dummy_feature_20",
- "_dummy_feature_40",
- "_dummy_feature_80",
+ "_feature_02",
+ "_feature_04",
+ "_feature_08",
+ "_feature_10",
+ "_feature_20",
+ "_feature_40",
+ "_feature_80",
]
-__all__ = ["all_feature_names"] + all_feature_names
+__all__ = ["all_feature_names", "set_selection", "info"] + all_feature_names
snake_case = 1
-_dummy_feature_02 = 0x02
-_dummy_feature_04 = 0x04
-_dummy_feature_08 = 0x08
-_dummy_feature_10 = 0x10
-_dummy_feature_20 = 0x20
-_dummy_feature_40 = 0x40
-_dummy_feature_80 = 0x80
+_feature_02 = 0x02
+_feature_04 = 0x04
+_feature_08 = 0x08
+_feature_10 = 0x10
+_feature_20 = 0x20
+_feature_40 = 0x40
+_feature_80 = 0x80
# let's remove the dummies for the normal user
_really_all_feature_names = all_feature_names[:]
@@ -91,9 +101,20 @@ Note: This are two imports.
12 LOAD_CONST 0 (None)
14 RETURN_VALUE
"""
-# XXX build an improved C version
+# XXX build an improved C version? I guess not.
def _import(name, *args, **kwargs):
+ importing_module = sys._getframe(1).f_globals['__name__']
+ existing = pyside_feature_dict.get(importing_module, 0)
+
if name == "__feature__" and args[2]:
+ global _is_initialized
+ if not _is_initialized:
+ # use _one_ recursive import...
+ import PySide2.QtCore
+ # Initialize all prior imported modules
+ for name in sys.modules:
+ pyside_feature_dict.setdefault(name, -1)
+
# This is an `import from` statement that corresponds to `IMPORT_NAME`.
# The following `IMPORT_FROM` will handle errors. (Confusing, ofc.)
flag = 0
@@ -102,13 +123,60 @@ def _import(name, *args, **kwargs):
flag |= globals()[feature]
else:
raise SyntaxError("PySide feature {} is not defined".format(feature))
- importing_module = sys._getframe(1).f_globals['__name__']
- existing = pyside_feature_dict.get(importing_module, 0)
- if isinstance(existing, int):
- flag |= existing & 255
+
+ flag |= existing & 255 if isinstance(existing, int) and existing >= 0 else 0
pyside_feature_dict[importing_module] = flag
+
if importing_module == "__main__":
# We need to add all modules here which should see __feature__.
pyside_feature_dict["rlcompleter"] = flag
+
+ # Initialize feature (multiple times allowed) and clear cache.
+ sys.modules["PySide2.QtCore"].__init_feature__()
return sys.modules["__feature__"]
+
+ if name.split(".")[0] == "PySide2":
+ # This is a module that imports PySide2.
+ flag = existing if isinstance(existing, int) else 0
+ else:
+ # This is some other module. Ignore it in switching.
+ flag = -1
+ pyside_feature_dict[importing_module] = flag
return original_import(name, *args, **kwargs)
+
+_is_initialized = False
+
+
+def set_selection(select_id, mod_name=None):
+ """
+ Internal use: Set the feature directly by Id.
+ Id == -1: ignore this module in switching.
+ """
+ mod_name = mod_name or sys._getframe(1).f_globals['__name__']
+ # Reset the features to the given id
+ flag = 0
+ if isinstance(select_id, int):
+ flag = select_id & 255
+ pyside_feature_dict[importing_module] = flag
+ sys.modules["PySide2.QtCore"].__init_feature__()
+ return _current_selection(flag)
+
+
+def info(mod_name=None):
+ """
+ Internal use: Return the current selection
+ """
+ mod_name = mod_name or sys._getframe(1).f_globals['__name__']
+ flag = pyside_feature_dict.get(mod_name, 0)
+ return _current_selection(flag)
+
+
+def _current_selection(flag):
+ names = []
+ if flag >= 0:
+ for idx, name in enumerate(_really_all_feature_names):
+ if (1 << idx) & flag:
+ names.append(name)
+ return names
+
+#eof