diff options
author | Christian Tismer <tismer@stackless.com> | 2020-06-13 00:41:37 +0200 |
---|---|---|
committer | Christian Tismer <tismer@stackless.com> | 2020-07-10 11:06:45 +0200 |
commit | 9a8beeeccf8c097cc4e6a216813353e67ac95ecc (patch) | |
tree | fe29c7748dc7abb0c18bbefaee5b639b0d9dad25 /sources/shiboken2/libshiboken | |
parent | 3d4d91334dc608a41963d9acb5080139202f33c5 (diff) |
feature-select: Implement a selectable feature framework
This is the framework for selectable features.
There are no real features implemented.
Planned is a maximum of 8 features.
They are all implemented as a dummy for now.
The decision depends of the following setting at the beginning of
a module after PySide2 import:
from __feature__ import <feature name>
For more info, see the Jira issue, section
The Principle Of Selectable Features In PySide
Task-number: PYSIDE-1019
Change-Id: If355e9294b5c16090b39d30422a90ea9c8523390
Reviewed-by: Christian Tismer <tismer@stackless.com>
Diffstat (limited to 'sources/shiboken2/libshiboken')
-rw-r--r-- | sources/shiboken2/libshiboken/basewrapper.cpp | 39 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/basewrapper.h | 3 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/pep384impl.cpp | 53 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/pep384impl.h | 7 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/sbkstaticstrings.cpp | 3 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/sbkstaticstrings.h | 3 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/shiboken.h | 1 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/signature.cpp | 59 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/signature.h | 1 |
9 files changed, 110 insertions, 59 deletions
diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp index 4c15582e9..5c2dc7807 100644 --- a/sources/shiboken2/libshiboken/basewrapper.cpp +++ b/sources/shiboken2/libshiboken/basewrapper.cpp @@ -95,12 +95,31 @@ void Sbk_object_dealloc(PyObject *self) static void SbkObjectTypeDealloc(PyObject *pyObj); static PyObject *SbkObjectTypeTpNew(PyTypeObject *metatype, PyObject *args, PyObject *kwds); +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); +} + // 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 // it was not existing before. We add them both for clarity. static PyGetSetDef SbkObjectType_Type_getsetlist[] = { {const_cast<char *>("__signature__"), (getter)Sbk_TypeGet___signature__}, {const_cast<char *>("__doc__"), (getter)Sbk_TypeGet___doc__}, + {const_cast<char *>("__dict__"), (getter)Sbk_TypeGet___dict__}, {nullptr} // Sentinel }; @@ -121,8 +140,25 @@ 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 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)}, @@ -235,6 +271,9 @@ PyTypeObject *SbkObjectType_TypeF(void) { static PyTypeObject *type = nullptr; if (!type) { + // PYSIDE-1019: Insert the default tp_getattro explicitly here + // so we can overwrite it a bit. + type_getattro = PyType_Type.tp_getattro; SbkObjectType_Type_spec.basicsize = PepHeapType_SIZE + sizeof(SbkObjectTypePrivate); type = reinterpret_cast<PyTypeObject *>(SbkType_FromSpec(&SbkObjectType_Type_spec)); diff --git a/sources/shiboken2/libshiboken/basewrapper.h b/sources/shiboken2/libshiboken/basewrapper.h index 7248103cc..a4a8629fb 100644 --- a/sources/shiboken2/libshiboken/basewrapper.h +++ b/sources/shiboken2/libshiboken/basewrapper.h @@ -93,6 +93,9 @@ typedef void (*ObjectDestructor)(void *); typedef void (*SubTypeInitHook)(SbkObjectType *, PyObject *, PyObject *); +typedef PyObject *(*SelectableFeatureHook)(PyTypeObject *); +LIBSHIBOKEN_API void initSelectableFeature(SelectableFeatureHook func); + extern LIBSHIBOKEN_API PyTypeObject *SbkObjectType_TypeF(void); extern LIBSHIBOKEN_API SbkObjectType *SbkObject_TypeF(void); diff --git a/sources/shiboken2/libshiboken/pep384impl.cpp b/sources/shiboken2/libshiboken/pep384impl.cpp index 5e0053e2e..4149bbcbf 100644 --- a/sources/shiboken2/libshiboken/pep384impl.cpp +++ b/sources/shiboken2/libshiboken/pep384impl.cpp @@ -78,14 +78,20 @@ static PyGetSetDef probe_getseters[] = { {nullptr} /* Sentinel */ }; +static PyMemberDef probe_members[] = { + {nullptr} /* Sentinel */ +}; + #define probe_tp_dealloc make_dummy(1) #define probe_tp_repr make_dummy(2) #define probe_tp_call make_dummy(3) +#define probe_tp_getattro make_dummy(16) #define probe_tp_str make_dummy(4) #define probe_tp_traverse make_dummy(5) #define probe_tp_clear make_dummy(6) #define probe_tp_iternext make_dummy(7) #define probe_tp_methods probe_methoddef +#define probe_tp_members probe_members #define probe_tp_getset probe_getseters #define probe_tp_descr_get make_dummy(10) #define probe_tp_init make_dummy(11) @@ -101,11 +107,13 @@ static PyType_Slot typeprobe_slots[] = { {Py_tp_dealloc, probe_tp_dealloc}, {Py_tp_repr, probe_tp_repr}, {Py_tp_call, probe_tp_call}, + {Py_tp_getattro, probe_tp_getattro}, {Py_tp_str, probe_tp_str}, {Py_tp_traverse, probe_tp_traverse}, {Py_tp_clear, probe_tp_clear}, {Py_tp_iternext, probe_tp_iternext}, {Py_tp_methods, probe_tp_methods}, + {Py_tp_members, probe_tp_members}, {Py_tp_getset, probe_tp_getset}, {Py_tp_descr_get, probe_tp_descr_get}, {Py_tp_init, probe_tp_init}, @@ -144,6 +152,7 @@ check_PyTypeObject_valid() || probe_tp_dealloc != check->tp_dealloc || probe_tp_repr != check->tp_repr || probe_tp_call != check->tp_call + || probe_tp_getattro != check->tp_getattro || probe_tp_str != check->tp_str || probe_tp_traverse != check->tp_traverse || probe_tp_clear != check->tp_clear @@ -427,27 +436,6 @@ PyRun_String(const char *str, int start, PyObject *globals, PyObject *locals) #endif // Py_LIMITED_API -// This is only a simple local helper that returns a computed variable. -// Used also in Python 2. -#if defined(Py_LIMITED_API) || defined(IS_PY2) -static PyObject * -PepRun_GetResult(const char *command) -{ - PyObject *d, *v, *res; - - d = PyDict_New(); - if (d == nullptr - || PyDict_SetItem(d, Shiboken::PyMagicName::builtins(), PyEval_GetBuiltins()) < 0) { - return nullptr; - } - v = PyRun_String(command, Py_file_input, d, d); - res = v ? PyDict_GetItem(d, Shiboken::PyName::result()) : nullptr; - Py_XDECREF(v); - Py_DECREF(d); - return res; -} -#endif // defined(Py_LIMITED_API) || defined(IS_PY2) - /***************************************************************************** * * Support for classobject.h @@ -669,6 +657,29 @@ PyImport_GetModule(PyObject *name) #endif // PY_VERSION_HEX < 0x03070000 || defined(Py_LIMITED_API) +// 2020-06-16: For simplicity of creating arbitrary things, this function +// is now made public. + +PyObject * +PepRun_GetResult(const char *command) +{ + /* + * Evaluate a string and return the variable `result` + */ + PyObject *d, *v, *res; + + d = PyDict_New(); + if (d == nullptr + || PyDict_SetItem(d, Shiboken::PyMagicName::builtins(), PyEval_GetBuiltins()) < 0) { + return nullptr; + } + v = PyRun_String(command, Py_file_input, d, d); + res = v ? PyDict_GetItem(d, Shiboken::PyName::result()) : nullptr; + Py_XDECREF(v); + Py_DECREF(d); + return res; +} + /***************************************************************************** * * Python 2 incompatibilities diff --git a/sources/shiboken2/libshiboken/pep384impl.h b/sources/shiboken2/libshiboken/pep384impl.h index 2bfe52254..2a14d6543 100644 --- a/sources/shiboken2/libshiboken/pep384impl.h +++ b/sources/shiboken2/libshiboken/pep384impl.h @@ -98,7 +98,7 @@ typedef struct _typeobject { void *X13; // hashfunc tp_hash; ternaryfunc tp_call; reprfunc tp_str; - void *X16; // getattrofunc tp_getattro; + getattrofunc tp_getattro; void *X17; // setattrofunc tp_setattro; void *X18; // PyBufferProcs *tp_as_buffer; unsigned long tp_flags; @@ -110,7 +110,7 @@ typedef struct _typeobject { void *X25; // getiterfunc tp_iter; iternextfunc tp_iternext; struct PyMethodDef *tp_methods; - void *X28; // struct PyMemberDef *tp_members; + struct PyMemberDef *tp_members; struct PyGetSetDef *tp_getset; struct _typeobject *tp_base; PyObject *tp_dict; @@ -531,6 +531,9 @@ extern LIBSHIBOKEN_API PyTypeObject *PepMethodDescr_TypePtr; LIBSHIBOKEN_API PyObject *PyImport_GetModule(PyObject *name); #endif // PY_VERSION_HEX < 0x03070000 || defined(Py_LIMITED_API) +// Evaluate a script and return the variable `result` +LIBSHIBOKEN_API PyObject *PepRun_GetResult(const char *command); + /***************************************************************************** * * Python 2 incompatibilities diff --git a/sources/shiboken2/libshiboken/sbkstaticstrings.cpp b/sources/shiboken2/libshiboken/sbkstaticstrings.cpp index 541d74918..9dd98eef3 100644 --- a/sources/shiboken2/libshiboken/sbkstaticstrings.cpp +++ b/sources/shiboken2/libshiboken/sbkstaticstrings.cpp @@ -52,9 +52,11 @@ namespace Shiboken { namespace PyName { // exported: +STATIC_STRING_IMPL(dict_ring, "dict_ring") STATIC_STRING_IMPL(dumps, "dumps") STATIC_STRING_IMPL(loads, "loads") STATIC_STRING_IMPL(result, "result") +STATIC_STRING_IMPL(select_id, "select_id") STATIC_STRING_IMPL(value, "value") STATIC_STRING_IMPL(values, "values") @@ -75,6 +77,7 @@ STATIC_STRING_IMPL(staticmethod, "staticmethod") namespace PyMagicName { // exported: STATIC_STRING_IMPL(class_, "__class__") +STATIC_STRING_IMPL(dict, "__dict__") STATIC_STRING_IMPL(ecf, "__ecf__") STATIC_STRING_IMPL(file, "__file__") STATIC_STRING_IMPL(members, "__members__") diff --git a/sources/shiboken2/libshiboken/sbkstaticstrings.h b/sources/shiboken2/libshiboken/sbkstaticstrings.h index 4078d163c..ebb64579c 100644 --- a/sources/shiboken2/libshiboken/sbkstaticstrings.h +++ b/sources/shiboken2/libshiboken/sbkstaticstrings.h @@ -49,11 +49,13 @@ namespace Shiboken namespace PyName { LIBSHIBOKEN_API PyObject *co_name(); +LIBSHIBOKEN_API PyObject *dict_ring(); LIBSHIBOKEN_API PyObject *dumps(); LIBSHIBOKEN_API PyObject *f_code(); LIBSHIBOKEN_API PyObject *f_lineno(); LIBSHIBOKEN_API PyObject *loads(); LIBSHIBOKEN_API PyObject *result(); +LIBSHIBOKEN_API PyObject *select_id(); LIBSHIBOKEN_API PyObject *value(); LIBSHIBOKEN_API PyObject *values(); } // namespace PyName @@ -61,6 +63,7 @@ LIBSHIBOKEN_API PyObject *values(); namespace PyMagicName { LIBSHIBOKEN_API PyObject *class_(); +LIBSHIBOKEN_API PyObject *dict(); LIBSHIBOKEN_API PyObject *ecf(); LIBSHIBOKEN_API PyObject *file(); LIBSHIBOKEN_API PyObject *members(); diff --git a/sources/shiboken2/libshiboken/shiboken.h b/sources/shiboken2/libshiboken/shiboken.h index 0d2d6b0a6..3e1df5235 100644 --- a/sources/shiboken2/libshiboken/shiboken.h +++ b/sources/shiboken2/libshiboken/shiboken.h @@ -55,6 +55,7 @@ #include "sbkstaticstrings.h" #include "shibokenmacros.h" #include "shibokenbuffer.h" +#include "signature.h" #endif // SHIBOKEN_H diff --git a/sources/shiboken2/libshiboken/signature.cpp b/sources/shiboken2/libshiboken/signature.cpp index b09b68d47..4614a131e 100644 --- a/sources/shiboken2/libshiboken/signature.cpp +++ b/sources/shiboken2/libshiboken/signature.cpp @@ -74,8 +74,8 @@ typedef struct safe_globals_struc { PyObject *helper_module; PyObject *arg_dict; PyObject *map_dict; - PyObject *value_dict; // for writing signatures - PyObject *feature_dict; // registry for PySide.__feature__ + PyObject *value_dict; // for writing signatures + PyObject *feature_dict; // registry for PySide.support.__feature__ // init part 2: run module PyObject *pyside_type_init_func; PyObject *create_signature_func; @@ -653,22 +653,17 @@ _fixup_getset(PyTypeObject *type, const char *name, PyGetSetDef *new_gsp) } } } - 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); + // staticmethod has just a __doc__ in the class + assert(strcmp(type->tp_name, "staticmethod") == 0); return 0; } static int -add_more_getsets(PyTypeObject *type, PyGetSetDef *gsp, PyObject **doc_descr) +add_more_getsets(PyTypeObject *type, PyGetSetDef *gsp, PyObject **old_descr) { /* - * This function is used to assign a new `__signature__` attribute, - * and also to override a `__doc__` or `__name__` attribute. + * This function is used to assign a new __signature__ attribute, + * and also to override a __doc__ attribute. */ assert(PyType_Check(type)); PyType_Ready(type); @@ -676,11 +671,9 @@ add_more_getsets(PyTypeObject *type, PyGetSetDef *gsp, PyObject **doc_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); - if (strcmp(gsp->name, "__doc__") == 0) - *doc_descr = have_descr; - else - assert(false); + *old_descr = have_descr; if (!_fixup_getset(type, gsp->name, gsp)) continue; } @@ -831,7 +824,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. // @@ -916,25 +909,13 @@ 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, 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 + || 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 ) return -1; #ifndef _WIN32 @@ -1233,8 +1214,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! */ - if ( PySide_PatchTypes() < 0 - || PySide_FinishSignatures(module, signatures) < 0) { + PySide_PatchTypes(); + if (PySide_FinishSignatures(module, signatures) < 0) { PyErr_Print(); PyErr_SetNone(PyExc_ImportError); } @@ -1285,4 +1266,10 @@ PyObject *Sbk_TypeGet___doc__(PyObject *ob) return pyside_tp_get___doc__(ob); } +PyObject *GetFeatureDict() +{ + init_module_1(); + return pyside_globals->feature_dict; +} + } //extern "C" diff --git a/sources/shiboken2/libshiboken/signature.h b/sources/shiboken2/libshiboken/signature.h index b22a78497..2a69df9cf 100644 --- a/sources/shiboken2/libshiboken/signature.h +++ b/sources/shiboken2/libshiboken/signature.h @@ -50,6 +50,7 @@ LIBSHIBOKEN_API void FinishSignatureInitialization(PyObject *, const char *[]); LIBSHIBOKEN_API void SetError_Argument(PyObject *, const char *); LIBSHIBOKEN_API PyObject *Sbk_TypeGet___signature__(PyObject *, PyObject *); LIBSHIBOKEN_API PyObject *Sbk_TypeGet___doc__(PyObject *); +LIBSHIBOKEN_API PyObject *GetFeatureDict(); } // extern "C" |