aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken2
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken2')
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.cpp16
-rw-r--r--sources/shiboken2/libshiboken/basewrapper.cpp104
-rw-r--r--sources/shiboken2/libshiboken/basewrapper.h5
-rw-r--r--sources/shiboken2/libshiboken/bindingmanager.cpp28
-rw-r--r--sources/shiboken2/libshiboken/bindingmanager.h2
-rw-r--r--sources/shiboken2/libshiboken/pep384impl.cpp3
-rw-r--r--sources/shiboken2/libshiboken/pep384impl.h2
-rw-r--r--sources/shiboken2/libshiboken/sbkstring.cpp44
-rw-r--r--sources/shiboken2/libshiboken/sbkstring.h1
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__feature__.py7
10 files changed, 170 insertions, 42 deletions
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
index 069431e59..b10074f79 100644
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
@@ -313,6 +313,7 @@ void CppGenerator::generateClass(QTextStream &s, const GeneratorContext &classCo
<< "#include <pysideproperty.h>\n"
<< "#include <pyside.h>\n"
<< "#include <pysideqenum.h>\n"
+ << "#include <feature_select.h>\n"
<< "#include <qapp_macro.h>\n\n"
<< "QT_WARNING_DISABLE_DEPRECATED\n\n";
}
@@ -949,10 +950,10 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s,
s << INDENT << returnStatement << '\n';
}
- s << INDENT << "static PyObject *pyFuncName = Shiboken::String::createStaticString(\""
- << funcName << "\");\n";
+ s << INDENT << "static PyObject *nameCache[2] = {};\n";
+ s << INDENT << "static const char *funcName = \"" << funcName << "\";\n";
s << INDENT << "Shiboken::AutoDecRef " << PYTHON_OVERRIDE_VAR
- << "(Shiboken::BindingManager::instance().getOverride(this, pyFuncName));\n";
+ << "(Shiboken::BindingManager::instance().getOverride(this, nameCache, funcName));\n";
s << INDENT << "if (" << PYTHON_OVERRIDE_VAR << ".isNull()) {\n";
{
Indentation indentation(INDENT);
@@ -5371,6 +5372,11 @@ void CppGenerator::writeSetattroFunction(QTextStream &s, AttroCheck attroCheck,
Q_ASSERT(!context.forSmartPointer());
const AbstractMetaClass *metaClass = context.metaClass();
writeSetattroDefinition(s, metaClass);
+
+ // PYSIDE-1019: Switch tp_dict before doing tp_setattro.
+ if (usePySideExtensions())
+ s << INDENT << "PySide::Feature::Select(self);\n";
+
// PYSIDE-803: Detect duck-punching; clear cache if a method is set.
if (attroCheck.testFlag(AttroCheckFlag::SetattroMethodOverride)
&& context.useWrapper()) {
@@ -5458,6 +5464,10 @@ void CppGenerator::writeGetattroFunction(QTextStream &s, AttroCheck attroCheck,
const AbstractMetaClass *metaClass = context.metaClass();
writeGetattroDefinition(s, metaClass);
+ // PYSIDE-1019: Switch tp_dict before doing tp_getattro.
+ if (usePySideExtensions())
+ s << INDENT << "PySide::Feature::Select(self);\n";
+
const QString getattrFunc = usePySideExtensions() && metaClass->isQObject()
? qObjectGetAttroFunction() : QLatin1String("PyObject_GenericGetAttr(self, name)");
diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp
index 5c2dc7807..a602688ec 100644
--- a/sources/shiboken2/libshiboken/basewrapper.cpp
+++ b/sources/shiboken2/libshiboken/basewrapper.cpp
@@ -97,21 +97,7 @@ static PyObject *SbkObjectTypeTpNew(PyTypeObject *metatype, PyObject *args, PyOb
static SelectableFeatureHook SelectFeatureSet = nullptr;
-void initSelectableFeature(SelectableFeatureHook func)
-{
- SelectFeatureSet = func;
-}
-
-// PYSIDE-1019: Switch type's tp_dict to the currently active namespace.
-static PyObject *Sbk_TypeGet___dict__(PyTypeObject *type, void *context)
-{
- auto dict = type->tp_dict;
- if (dict == NULL)
- Py_RETURN_NONE;
- if (SelectFeatureSet != nullptr)
- dict = SelectFeatureSet(type);
- return PyDictProxy_New(dict);
-}
+static PyObject *Sbk_TypeGet___dict__(PyTypeObject *type, void *context); // forward
// PYSIDE-908: The function PyType_Modified does not work in PySide, so we need to
// explicitly pass __doc__. For __signature__ it _did_ actually work, because
@@ -140,26 +126,12 @@ static PyObject *SbkObjectType_repr(PyObject *type)
#endif // PY_VERSION_HEX < 0x03000000
-// PYSIDE-1019: Switch type's tp_dict to the currently active namespace.
-static PyObject *(*type_getattro)(PyObject *type, PyObject *name);
-
-static PyObject *mangled_type_getattro(PyTypeObject *type, PyObject *name)
-{
- /*
- * Note: This `type_getattro` version is only the default that comes
- * from `PyType_Type.tp_getattro`. This does *not* interfere in any way
- * with the complex `tp_getattro` of `QObject` and other instances.
- * What we change here is the meta class of `QObject`.
- */
- if (SelectFeatureSet != nullptr)
- type->tp_dict = SelectFeatureSet(type);
- return type_getattro(reinterpret_cast<PyObject *>(type), name);
-}
+static PyObject *(*type_getattro)(PyObject *type, PyObject *name); // forward
+static PyObject *mangled_type_getattro(PyTypeObject *type, PyObject *name); // forward
static PyType_Slot SbkObjectType_Type_slots[] = {
{Py_tp_dealloc, reinterpret_cast<void *>(SbkObjectTypeDealloc)},
{Py_tp_getattro, reinterpret_cast<void *>(mangled_type_getattro)},
- {Py_tp_setattro, reinterpret_cast<void *>(PyObject_GenericSetAttr)},
{Py_tp_base, static_cast<void *>(&PyType_Type)},
{Py_tp_alloc, reinterpret_cast<void *>(PyType_GenericAlloc)},
{Py_tp_new, reinterpret_cast<void *>(SbkObjectTypeTpNew)},
@@ -340,7 +312,12 @@ static int SbkObject_clear(PyObject *self)
return 0;
}
+static PyObject *SbkObject_GenericGetAttr(PyObject *obj, PyObject *name);
+static int SbkObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *value);
+
static PyType_Slot SbkObject_Type_slots[] = {
+ {Py_tp_getattro, reinterpret_cast<void *>(SbkObject_GenericGetAttr)},
+ {Py_tp_setattro, reinterpret_cast<void *>(SbkObject_GenericSetAttr)},
{Py_tp_dealloc, reinterpret_cast<void *>(SbkDeallocWrapperWithPrivateDtor)},
{Py_tp_traverse, reinterpret_cast<void *>(SbkObject_traverse)},
{Py_tp_clear, reinterpret_cast<void *>(SbkObject_clear)},
@@ -533,6 +510,71 @@ 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
+//
+
+void initSelectableFeature(SelectableFeatureHook func)
+{
+ SelectFeatureSet = func;
+}
+
+static PyObject *mangled_type_getattro(PyTypeObject *type, PyObject *name)
+{
+ /*
+ * Note: This `type_getattro` version is only the default that comes
+ * from `PyType_Type.tp_getattro`. This does *not* interfere in any way
+ * with the complex `tp_getattro` of `QObject` and other instances.
+ * What we change here is the meta class of `QObject`.
+ */
+ if (SelectFeatureSet != nullptr)
+ type->tp_dict = SelectFeatureSet(type);
+ return type_getattro(reinterpret_cast<PyObject *>(type), name);
+}
+
+static PyObject *Sbk_TypeGet___dict__(PyTypeObject *type, void *context)
+{
+ /*
+ * This is the override for getting a dict.
+ */
+ auto dict = type->tp_dict;
+ if (dict == NULL)
+ Py_RETURN_NONE;
+ if (SelectFeatureSet != nullptr)
+ dict = SelectFeatureSet(type);
+ return PyDictProxy_New(dict);
+}
+
+// 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
+static PyObject *SbkObject_GenericGetAttr(PyObject *obj, PyObject *name)
+{
+ auto type = Py_TYPE(obj);
+ if (SelectFeatureSet != nullptr)
+ type->tp_dict = SelectFeatureSet(type);
+ return PyObject_GenericGetAttr(obj, name);
+}
+
+static int SbkObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *value)
+{
+ auto type = Py_TYPE(obj);
+ if (SelectFeatureSet != nullptr)
+ type->tp_dict = SelectFeatureSet(type);
+ return PyObject_GenericSetAttr(obj, name, value);
+}
+
+//
+//////////////////////////////////////////////////////////////////////////////
+
static PyObject *SbkObjectTypeTpNew(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
{
// Check if all bases are new style before calling type.tp_new
diff --git a/sources/shiboken2/libshiboken/basewrapper.h b/sources/shiboken2/libshiboken/basewrapper.h
index a4a8629fb..47ea89577 100644
--- a/sources/shiboken2/libshiboken/basewrapper.h
+++ b/sources/shiboken2/libshiboken/basewrapper.h
@@ -93,9 +93,14 @@ typedef void (*ObjectDestructor)(void *);
typedef void (*SubTypeInitHook)(SbkObjectType *, PyObject *, PyObject *);
+// PYSIDE-1019: Set the function to select the current feature.
typedef PyObject *(*SelectableFeatureHook)(PyTypeObject *);
LIBSHIBOKEN_API void initSelectableFeature(SelectableFeatureHook func);
+// PYSIDE-1019: Publish the start of setattro.
+LIBSHIBOKEN_API void SbkObject_NotifySetAttr(PyObject *obj, PyObject *name, PyObject *value);
+
+
extern LIBSHIBOKEN_API PyTypeObject *SbkObjectType_TypeF(void);
extern LIBSHIBOKEN_API SbkObjectType *SbkObject_TypeF(void);
diff --git a/sources/shiboken2/libshiboken/bindingmanager.cpp b/sources/shiboken2/libshiboken/bindingmanager.cpp
index 1c38da81c..b35a02ef4 100644
--- a/sources/shiboken2/libshiboken/bindingmanager.cpp
+++ b/sources/shiboken2/libshiboken/bindingmanager.cpp
@@ -44,6 +44,7 @@
#include "sbkdbg.h"
#include "gilstate.h"
#include "sbkstring.h"
+#include "sbkstaticstrings.h"
#include "debugfreehook.h"
#include <cstddef>
@@ -273,7 +274,19 @@ SbkObject *BindingManager::retrieveWrapper(const void *cptr)
return iter->second;
}
-PyObject *BindingManager::getOverride(const void *cptr, PyObject *methodName)
+static 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;
+}
+
+PyObject *BindingManager::getOverride(const void *cptr, PyObject *methodNameCache[2], const char *methodName)
{
SbkObject *wrapper = retrieveWrapper(cptr);
// The refcount can be 0 if the object is dieing and someone called
@@ -281,15 +294,22 @@ PyObject *BindingManager::getOverride(const void *cptr, PyObject *methodName)
if (!wrapper || reinterpret_cast<const PyObject *>(wrapper)->ob_refcnt == 0)
return nullptr;
+ bool flag = mangleNameFlag(Py_TYPE(wrapper));
+ PyObject *pyMethodName = methodNameCache[flag]; // borrowed
+ if (pyMethodName == nullptr) {
+ pyMethodName = Shiboken::String::getSnakeCaseName(methodName, flag);
+ methodNameCache[flag] = pyMethodName;
+ }
+
if (wrapper->ob_dict) {
- PyObject *method = PyDict_GetItem(wrapper->ob_dict, methodName);
+ PyObject *method = PyDict_GetItem(wrapper->ob_dict, pyMethodName);
if (method) {
Py_INCREF(reinterpret_cast<PyObject *>(method));
return method;
}
}
- PyObject *method = PyObject_GetAttr(reinterpret_cast<PyObject *>(wrapper), methodName);
+ PyObject *method = PyObject_GetAttr(reinterpret_cast<PyObject *>(wrapper), pyMethodName);
if (method && PyMethod_Check(method)
&& PyMethod_GET_SELF(method) == reinterpret_cast<PyObject *>(wrapper)) {
@@ -301,7 +321,7 @@ PyObject *BindingManager::getOverride(const void *cptr, PyObject *methodName)
for (int i = 1; i < PyTuple_GET_SIZE(mro) - 1; i++) {
auto *parent = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, i));
if (parent->tp_dict) {
- defaultMethod = PyDict_GetItem(parent->tp_dict, methodName);
+ defaultMethod = PyDict_GetItem(parent->tp_dict, pyMethodName);
if (defaultMethod && PyMethod_GET_FUNCTION(method) != defaultMethod)
return method;
}
diff --git a/sources/shiboken2/libshiboken/bindingmanager.h b/sources/shiboken2/libshiboken/bindingmanager.h
index 0bcde196f..8882f402e 100644
--- a/sources/shiboken2/libshiboken/bindingmanager.h
+++ b/sources/shiboken2/libshiboken/bindingmanager.h
@@ -73,7 +73,7 @@ public:
void addToDeletionInMainThread(const DestructorEntry &);
SbkObject *retrieveWrapper(const void *cptr);
- PyObject *getOverride(const void *cptr, PyObject *methodName);
+ PyObject *getOverride(const void *cptr, PyObject *methodNameCache[2], const char *methodName);
void addClassInheritance(SbkObjectType *parent, SbkObjectType *child);
/**
diff --git a/sources/shiboken2/libshiboken/pep384impl.cpp b/sources/shiboken2/libshiboken/pep384impl.cpp
index 4149bbcbf..57d3de261 100644
--- a/sources/shiboken2/libshiboken/pep384impl.cpp
+++ b/sources/shiboken2/libshiboken/pep384impl.cpp
@@ -86,6 +86,7 @@ static PyMemberDef probe_members[] = {
#define probe_tp_repr make_dummy(2)
#define probe_tp_call make_dummy(3)
#define probe_tp_getattro make_dummy(16)
+#define probe_tp_setattro make_dummy(17)
#define probe_tp_str make_dummy(4)
#define probe_tp_traverse make_dummy(5)
#define probe_tp_clear make_dummy(6)
@@ -108,6 +109,7 @@ static PyType_Slot typeprobe_slots[] = {
{Py_tp_repr, probe_tp_repr},
{Py_tp_call, probe_tp_call},
{Py_tp_getattro, probe_tp_getattro},
+ {Py_tp_setattro, probe_tp_setattro},
{Py_tp_str, probe_tp_str},
{Py_tp_traverse, probe_tp_traverse},
{Py_tp_clear, probe_tp_clear},
@@ -153,6 +155,7 @@ check_PyTypeObject_valid()
|| probe_tp_repr != check->tp_repr
|| probe_tp_call != check->tp_call
|| probe_tp_getattro != check->tp_getattro
+ || probe_tp_setattro != check->tp_setattro
|| probe_tp_str != check->tp_str
|| probe_tp_traverse != check->tp_traverse
|| probe_tp_clear != check->tp_clear
diff --git a/sources/shiboken2/libshiboken/pep384impl.h b/sources/shiboken2/libshiboken/pep384impl.h
index 2a14d6543..973cf06ce 100644
--- a/sources/shiboken2/libshiboken/pep384impl.h
+++ b/sources/shiboken2/libshiboken/pep384impl.h
@@ -99,7 +99,7 @@ typedef struct _typeobject {
ternaryfunc tp_call;
reprfunc tp_str;
getattrofunc tp_getattro;
- void *X17; // setattrofunc tp_setattro;
+ setattrofunc tp_setattro;
void *X18; // PyBufferProcs *tp_as_buffer;
unsigned long tp_flags;
void *X20; // const char *tp_doc;
diff --git a/sources/shiboken2/libshiboken/sbkstring.cpp b/sources/shiboken2/libshiboken/sbkstring.cpp
index 092745d3d..ed8b61fc8 100644
--- a/sources/shiboken2/libshiboken/sbkstring.cpp
+++ b/sources/shiboken2/libshiboken/sbkstring.cpp
@@ -271,5 +271,49 @@ PyObject *createStaticString(const char *str)
return result;
}
+///////////////////////////////////////////////////////////////////////
+//
+// PYSIDE-1019: Helper function for snake_case vs. camelCase names
+// ---------------------------------------------------------------
+//
+// When renaming dict entries, `BindingManager::getOverride` must
+// use adapted names.
+//
+// This might become more complex when we need to register
+// exceptions from this rule.
+//
+
+PyObject *getSnakeCaseName(const char *name, bool lower)
+{
+ /*
+ * Convert `camelCase` to `snake_case`.
+ * Gives up when there are two consecutive upper chars.
+ *
+ * Also functions beginning with `gl` followed by upper case stay
+ * unchanged since that are the special OpenGL functions.
+ */
+ if (!lower
+ || strlen(name) < 3
+ || (name[0] == 'g' && name[1] == 'l' && isupper(name[2])))
+ return createStaticString(name);
+
+ char new_name[200 + 1] = {};
+ const char *p = name;
+ char *q = new_name;
+ for (; *p && q - new_name < 200; ++p, ++q) {
+ if (isupper(*p)) {
+ if (p != name && isupper(*(p - 1)))
+ return createStaticString(name);
+ *q = '_';
+ ++q;
+ *q = tolower(*p);
+ }
+ else {
+ *q = *p;
+ }
+ }
+ return createStaticString(new_name);
+}
+
} // namespace String
} // namespace Shiboken
diff --git a/sources/shiboken2/libshiboken/sbkstring.h b/sources/shiboken2/libshiboken/sbkstring.h
index 84d7768c5..3475d3acd 100644
--- a/sources/shiboken2/libshiboken/sbkstring.h
+++ b/sources/shiboken2/libshiboken/sbkstring.h
@@ -61,6 +61,7 @@ namespace String
LIBSHIBOKEN_API int compare(PyObject *val1, const char *val2);
LIBSHIBOKEN_API Py_ssize_t len(PyObject *str);
LIBSHIBOKEN_API PyObject *createStaticString(const char *str);
+ LIBSHIBOKEN_API PyObject *getSnakeCaseName(const char *name, bool lower);
} // namespace String
} // namespace Shiboken
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__feature__.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__feature__.py
index 58c1ff925..d088ea41b 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__feature__.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__feature__.py
@@ -49,7 +49,7 @@ similarity to Python's `__future__` file, but also some distinction.
import sys
all_feature_names = [
- "_dummy_feature_01",
+ "snake_case",
"_dummy_feature_02",
"_dummy_feature_04",
"_dummy_feature_08",
@@ -61,7 +61,7 @@ all_feature_names = [
__all__ = ["all_feature_names"] + all_feature_names
-_dummy_feature_01 = 0x01
+snake_case = 1
_dummy_feature_02 = 0x02
_dummy_feature_04 = 0x04
_dummy_feature_08 = 0x08
@@ -107,5 +107,8 @@ def _import(name, *args, **kwargs):
if isinstance(existing, int):
flag |= existing & 255
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
return sys.modules["__feature__"]
return original_import(name, *args, **kwargs)