aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Tismer <tismer@stackless.com>2020-09-27 14:39:25 +0200
committerChristian Tismer <tismer@stackless.com>2020-09-29 09:27:53 +0200
commit11179f639531c1c880498196382678b31974247d (patch)
treed1695067feb3fea621a1ee79d615f1263a2edb7f
parent50247e7d4a67e892a85dff7472f889bac97c91c7 (diff)
Feature-select: Implement signature-awareness of snake_case
After implementing selectable features, support from the signature module was quite much missing. It was not clear for some time what to do the best. It turned out to have the smallest impact and runtime penalty to use the Python parser output dictionaries and create copies with snake case naming. That has almost no overhead. Also, it was necessary to augment the internal map_dict with snake_case versions. It may be possible to simplify that map_dict further in another check-in. Remaining is the problem of static properties. This will be tried using the PySide Property objects which can be improved. Change-Id: Ied83ccb197a3c15932c4202b5f1ade772416e17b Task-number: PYSIDE-1019 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
-rw-r--r--sources/pyside2/libpyside/feature_select.cpp32
-rw-r--r--sources/shiboken2/libshiboken/sbkstaticstrings.cpp2
-rw-r--r--sources/shiboken2/libshiboken/sbkstaticstrings.h2
-rw-r--r--sources/shiboken2/libshiboken/signature/signature.cpp3
-rw-r--r--sources/shiboken2/libshiboken/signature/signature_helper.cpp73
-rw-r--r--sources/shiboken2/libshiboken/signature/signature_p.h1
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py5
7 files changed, 85 insertions, 33 deletions
diff --git a/sources/pyside2/libpyside/feature_select.cpp b/sources/pyside2/libpyside/feature_select.cpp
index a1ba76251..b26810add 100644
--- a/sources/pyside2/libpyside/feature_select.cpp
+++ b/sources/pyside2/libpyside/feature_select.cpp
@@ -546,40 +546,17 @@ static bool feature_01_addLowerNames(PyTypeObject *type, PyObject *prev_dict, in
// Feature 0x02: Use true properties instead of getters and setters
//
-static PyObject *createProperty(PyObject *getter, PyObject *setter, PyObject *doc)
+static PyObject *createProperty(PyObject *getter, PyObject *setter)
{
assert(getter != nullptr);
if (setter == nullptr)
setter = Py_None;
- PyObject *deleter = Py_None;
PyObject *prop = PyObject_CallObject(reinterpret_cast<PyObject *>(&PyProperty_Type), nullptr);
- AutoDecRef args(Py_BuildValue("OOOO", getter, setter, deleter, doc));
+ AutoDecRef args(Py_BuildValue("OO", getter, setter));
PyProperty_Type.tp_init(prop, args, nullptr);
return prop;
}
-static PyObject *calcPropDocString(PyTypeObject *type, PyObject *getterName, PyObject *setterName)
-{
- // To calculate the docstring, we need the __doc__ attribute of the original
- // getter and setter. We temporatily switch back to no features. This
- // might change when we have full signature support for features.
- auto hold = type->tp_dict;
- moveToFeatureSet(type, fast_id_array[0]);
- auto dict = type->tp_dict;
- auto getter = PyDict_GetItem(dict, getterName);
- auto setter = setterName ? PyDict_GetItem(dict, setterName) : nullptr;
- PyObject *buf = PyObject_GetAttr(getter, PyMagicName::doc());
- type->tp_dict = hold;
-
- if (setter == nullptr)
- return buf;
- AutoDecRef nl(Py_BuildValue("s", "\n"));
- AutoDecRef wdoc(PyObject_GetAttr(setter, PyMagicName::doc()));
- String::concat(&buf, nl);
- String::concat(&buf, wdoc);
- return buf;
-}
-
static QStringList parseFields(const char *propstr)
{
/*
@@ -639,10 +616,7 @@ static bool feature_02_true_property(PyTypeObject *type, PyObject *prev_dict, in
if (setter != nullptr && Py_TYPE(setter) != PepMethodDescr_TypePtr)
continue;
- PyObject *doc_read = make_snake_case(fields[1], false);
- PyObject *doc_write(haveWrite ? make_snake_case(fields[2], false) : nullptr);
- AutoDecRef doc(calcPropDocString(type, doc_read, doc_write));
- AutoDecRef PyProperty(createProperty(getter, setter, doc));
+ AutoDecRef PyProperty(createProperty(getter, setter));
if (PyProperty.isNull())
return false;
if (PyDict_SetItem(prop_dict, name, PyProperty) < 0)
diff --git a/sources/shiboken2/libshiboken/sbkstaticstrings.cpp b/sources/shiboken2/libshiboken/sbkstaticstrings.cpp
index 672be4009..5559d58d6 100644
--- a/sources/shiboken2/libshiboken/sbkstaticstrings.cpp
+++ b/sources/shiboken2/libshiboken/sbkstaticstrings.cpp
@@ -56,6 +56,8 @@ STATIC_STRING_IMPL(dumps, "dumps")
STATIC_STRING_IMPL(fget, "fget")
STATIC_STRING_IMPL(fset, "fset")
STATIC_STRING_IMPL(loads, "loads")
+STATIC_STRING_IMPL(multi, "multi")
+STATIC_STRING_IMPL(name, "name")
STATIC_STRING_IMPL(result, "result")
STATIC_STRING_IMPL(value, "value")
STATIC_STRING_IMPL(values, "values")
diff --git a/sources/shiboken2/libshiboken/sbkstaticstrings.h b/sources/shiboken2/libshiboken/sbkstaticstrings.h
index 09e22b395..b72fa989b 100644
--- a/sources/shiboken2/libshiboken/sbkstaticstrings.h
+++ b/sources/shiboken2/libshiboken/sbkstaticstrings.h
@@ -55,6 +55,8 @@ LIBSHIBOKEN_API PyObject *fset();
LIBSHIBOKEN_API PyObject *f_code();
LIBSHIBOKEN_API PyObject *f_lineno();
LIBSHIBOKEN_API PyObject *loads();
+LIBSHIBOKEN_API PyObject *multi();
+LIBSHIBOKEN_API PyObject *name();
LIBSHIBOKEN_API PyObject *result();
LIBSHIBOKEN_API PyObject *value();
LIBSHIBOKEN_API PyObject *values();
diff --git a/sources/shiboken2/libshiboken/signature/signature.cpp b/sources/shiboken2/libshiboken/signature/signature.cpp
index 76a71b00b..085d751aa 100644
--- a/sources/shiboken2/libshiboken/signature/signature.cpp
+++ b/sources/shiboken2/libshiboken/signature/signature.cpp
@@ -343,6 +343,9 @@ PyObject *PySide_BuildSignatureProps(PyObject *type_key)
empty_dict = PyDict_New();
return empty_dict;
}
+ // PYSIDE-1019: Build snake case versions of the functions.
+ if (insert_snake_case_variants(dict) < 0)
+ return nullptr;
// We replace the arguments by the result dict.
if (PyDict_SetItem(pyside_globals->arg_dict, type_key, dict) < 0)
return nullptr;
diff --git a/sources/shiboken2/libshiboken/signature/signature_helper.cpp b/sources/shiboken2/libshiboken/signature/signature_helper.cpp
index 7e92a9861..2b360c786 100644
--- a/sources/shiboken2/libshiboken/signature/signature_helper.cpp
+++ b/sources/shiboken2/libshiboken/signature/signature_helper.cpp
@@ -150,6 +150,28 @@ static PyObject *compute_name_key(PyObject *ob)
return Py_BuildValue("(OO)", type_key.object(), func_name.object());
}
+static PyObject *_func_with_new_name(PyTypeObject *type,
+ PyMethodDef *meth,
+ const char *new_name)
+{
+ /*
+ * Create a function with a lower case name.
+ * Note: This is similar to feature_select's methodWithNewName,
+ * but does not create a descriptor.
+ * XXX Maybe we can get rid of this, completely?
+ */
+ auto obtype = reinterpret_cast<PyObject *>(type);
+ int len = strlen(new_name);
+ auto name = new char[len + 1];
+ strcpy(name, new_name);
+ auto new_meth = new PyMethodDef;
+ new_meth->ml_name = name;
+ new_meth->ml_meth = meth->ml_meth;
+ new_meth->ml_flags = meth->ml_flags;
+ new_meth->ml_doc = meth->ml_doc;
+ return PyCFunction_NewEx(new_meth, obtype, nullptr);
+}
+
static int build_name_key_to_func(PyObject *obtype)
{
auto *type = reinterpret_cast<PyTypeObject *>(obtype);
@@ -167,6 +189,17 @@ static int build_name_key_to_func(PyObject *obtype)
|| PyDict_SetItem(pyside_globals->map_dict, name_key, func) < 0)
return -1;
}
+ // PYSIDE-1019: Now we repeat the same for snake case names.
+ meth = type->tp_methods;
+ for (; meth->ml_name != nullptr; meth++) {
+ const char *name = String::toCString(String::getSnakeCaseName(meth->ml_name, true));
+ AutoDecRef func(_func_with_new_name(type, meth, name));
+ AutoDecRef func_name(get_funcname(func));
+ AutoDecRef name_key(Py_BuildValue("(OO)", type_key.object(), func_name.object()));
+ if (func.isNull() || name_key.isNull()
+ || PyDict_SetItem(pyside_globals->map_dict, name_key, func) < 0)
+ return -1;
+ }
return 0;
}
@@ -198,6 +231,46 @@ PyObject *name_key_to_func(PyObject *ob)
return ret;
}
+static PyObject *_build_new_entry(PyObject *new_name, PyObject *value)
+{
+ PyObject *new_value = PyDict_Copy(value);
+ PyObject *multi = PyDict_GetItem(value, PyName::multi());
+ if (multi != nullptr && Py_TYPE(multi) == &PyList_Type) {
+ ssize_t len = PyList_Size(multi);
+ AutoDecRef list(PyList_New(len));
+ if (list.isNull())
+ return nullptr;
+ for (int idx = 0; idx < len; ++idx) {
+ auto multi_entry = PyList_GetItem(multi, idx);
+ auto dup = PyDict_Copy(multi_entry);
+ if (PyDict_SetItem(dup, PyName::name(), new_name) < 0)
+ return nullptr;
+ if (PyList_SetItem(list, idx, dup) < 0)
+ return nullptr;
+ }
+ if (PyDict_SetItem(new_value, PyName::multi(), list) < 0)
+ return nullptr;
+ } else {
+ if (PyDict_SetItem(new_value, PyName::name(), new_name) < 0)
+ return nullptr;
+ }
+ return new_value;
+}
+
+int insert_snake_case_variants(PyObject *dict)
+{
+ AutoDecRef snake_dict(PyDict_New());
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(dict, &pos, &key, &value)) {
+ AutoDecRef name(String::getSnakeCaseName(key, true));
+ AutoDecRef new_value(_build_new_entry(name, value));
+ if (PyDict_SetItem(snake_dict, name, new_value) < 0)
+ return -1;
+ }
+ return PyDict_Merge(dict, snake_dict, 0);
+}
+
PyObject *_get_class_of_cf(PyObject *ob_cf)
{
PyObject *selftype = PyCFunction_GET_SELF(ob_cf);
diff --git a/sources/shiboken2/libshiboken/signature/signature_p.h b/sources/shiboken2/libshiboken/signature/signature_p.h
index 9444f3e9b..ef7846472 100644
--- a/sources/shiboken2/libshiboken/signature/signature_p.h
+++ b/sources/shiboken2/libshiboken/signature/signature_p.h
@@ -95,6 +95,7 @@ PyObject *pyside_tp_get___doc__(PyObject *tp);
PyObject *_get_qualname(PyObject *ob);
int add_more_getsets(PyTypeObject *type, PyGetSetDef *gsp, PyObject **doc_descr);
PyObject *name_key_to_func(PyObject *ob);
+int insert_snake_case_variants(PyObject *dict);
PyObject *_get_class_of_cf(PyObject *ob_cf);
PyObject *_get_class_of_sm(PyObject *ob_sm);
PyObject *_get_class_of_descr(PyObject *ob);
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py
index 8a814114a..20c791cc1 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py
@@ -349,7 +349,6 @@ def calculate_props(line):
props.annotations = annotations
props.varnames = varnames = tuple(tup[0] for tup in arglist)
funcname = parsed.funcname
- props.fullname = funcname
shortname = funcname[funcname.rindex(".")+1:]
props.name = shortname
props.multi = parsed.multi
@@ -366,7 +365,6 @@ def fix_variables(props, line):
if retvar and isinstance(retvar, (ResultVariable, ArrayLikeVariable)):
# Special case: a ResultVariable which is the result will always be an array!
annos["return"] = retvar = typing.List[retvar.type]
- fullname = props.fullname
varnames = list(props.varnames)
defaults = list(props.defaults)
diff = len(varnames) - len(defaults)
@@ -456,8 +454,7 @@ def pyside_type_init(type_key, sig_strings):
multi_props.append(props)
if multi > 0:
continue
- fullname = props.pop("fullname")
- multi_props = {"multi": multi_props, "fullname": fullname}
+ multi_props = {"multi": multi_props}
ret[shortname] = multi_props
dprint(multi_props)
multi_props = []