diff options
| author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2020-08-17 07:41:37 +0200 |
|---|---|---|
| committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2020-08-17 07:41:37 +0200 |
| commit | f440ebfd838d0b754bbba38fbbd2ccf5318f7347 (patch) | |
| tree | 53d1431ceb7d64826a86f812c4b9a4fe3310f846 | |
| parent | 7a1fe1519159a8bcaa61aec35c1d942ed024bf73 (diff) | |
| parent | 58a0d36d9271e91bd21272a9fe3b736dd90db58d (diff) | |
Merge remote-tracking branch 'origin/5.15' into dev
Change-Id: Icee2cd5a37181070d8ef50e7143868d4f126cea5
| -rw-r--r-- | sources/pyside2/PySide2/QtCore/typesystem_core_common.xml | 4 | ||||
| -rw-r--r-- | sources/pyside2/PySide2/__init__.py.in | 16 | ||||
| -rw-r--r-- | sources/pyside2/PySide2/glue/qtcore.cpp | 4 | ||||
| -rw-r--r-- | sources/pyside2/libpyside/feature_select.cpp | 136 | ||||
| -rw-r--r-- | sources/pyside2/libpyside/pyside.cpp | 2 | ||||
| -rw-r--r-- | sources/pyside2/tests/QtCore/multiple_feature_test.py | 9 | ||||
| -rw-r--r-- | sources/shiboken2/generator/shiboken2/cppgenerator.cpp | 1 | ||||
| -rw-r--r-- | sources/shiboken2/libshiboken/basewrapper.cpp | 29 | ||||
| -rw-r--r-- | sources/shiboken2/libshiboken/basewrapper.h | 4 | ||||
| -rw-r--r-- | sources/shiboken2/libshiboken/basewrapper_p.h | 10 | ||||
| -rw-r--r-- | sources/shiboken2/libshiboken/bindingmanager.cpp | 10 | ||||
| -rw-r--r-- | sources/shiboken2/libshiboken/signature.cpp | 49 | ||||
| -rw-r--r-- | sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__feature__.py | 108 |
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 |
