aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Tismer <tismer@stackless.com>2020-08-13 16:10:10 +0200
committerChristian Tismer <tismer@stackless.com>2020-08-14 10:03:33 +0200
commit58a0d36d9271e91bd21272a9fe3b736dd90db58d (patch)
tree594e7b328845048e60a03de07aad10ea13099d91
parent4457db11f873b29bd46c268126cbbdea6b397eee (diff)
feature-select: delay the feature switching
Feature switching was written rather naively and happened after almost every module change which can occour very often. This patch is much more careful with switching and uses an ignore code to prevent switching when PySide was not imported at all. A potential regression when a switch is set before some PySide module is being imported and PepType_SOTP is zero was also solved. Task-number: PYSIDE-1019 Change-Id: I24dec7b3e4d0b577f77262392ded0b8a2006b3cc Reviewed-by: Christian Tismer <tismer@stackless.com>
-rw-r--r--sources/pyside2/libpyside/feature_select.cpp34
-rw-r--r--sources/shiboken2/libshiboken/basewrapper.cpp6
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__feature__.py110
3 files changed, 117 insertions, 33 deletions
diff --git a/sources/pyside2/libpyside/feature_select.cpp b/sources/pyside2/libpyside/feature_select.cpp
index c703d18c4..d3beeef7a 100644
--- a/sources/pyside2/libpyside/feature_select.cpp
+++ b/sources/pyside2/libpyside/feature_select.cpp
@@ -132,27 +132,33 @@ static FeatureProc *featurePointer = nullptr;
static PyObject *cached_globals = nullptr;
static PyObject *last_select_id = nullptr;
-static PyObject *fast_id_array[256] = {};
+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 = fast_id_array[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 == cached_globals)
+ if ( globals == nullptr
+ || globals == cached_globals)
return last_select_id;
PyObject *modname = PyDict_GetItem(globals, PyMagicName::name());
if (modname == nullptr)
- return zero;
+ return last_select_id;
+
PyObject *select_id = PyDict_GetItem(feature_dict, modname);
- if (select_id == nullptr || !PyInt_Check(select_id)) // int/long cheating
- return zero;
+ 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;
}
@@ -378,6 +384,12 @@ static inline PyObject *SelectFeatureSet(PyTypeObject *type)
}
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);
@@ -424,7 +436,7 @@ static FeatureProc featureProcArray[] = {
void finalize()
{
- for (int idx = 0; idx < 256; ++idx)
+ for (int idx = -1; idx < 256; ++idx)
Py_DECREF(fast_id_array[idx]);
}
@@ -433,8 +445,10 @@ void init()
// This function can be called multiple times.
static bool is_initialized = false;
if (!is_initialized) {
- for (int idx = 0; idx < 256; ++idx)
+ 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);
diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp
index 0d2a1975f..c3c16cb02 100644
--- a/sources/shiboken2/libshiboken/basewrapper.cpp
+++ b/sources/shiboken2/libshiboken/basewrapper.cpp
@@ -577,7 +577,11 @@ static int SbkObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *val
// Caching the select Id.
int SbkObjectType_GetReserved(PyTypeObject *type)
{
- return PepType_SOTP(reinterpret_cast<SbkObjectType *>(type))->pyside_reserved_bits;
+ 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)
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__feature__.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__feature__.py
index ca712bd9b..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,11 +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]:
- # Initialize feature (multiple times allowed) and clear cache.
- sys.modules["PySide2.QtCore"].__init_feature__()
+ 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
@@ -104,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