diff options
author | Cristián Maureira-Fredes <cristian.maureira-fredes@qt.io> | 2019-05-29 11:22:44 +0200 |
---|---|---|
committer | Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io> | 2019-07-17 10:47:31 +0200 |
commit | 78dad8180d797a647645b74255bfc29c46d7264a (patch) | |
tree | fa35a636fb31d0e0b56bb3acdbd56f123526a179 | |
parent | 4905e2e2feacd346c2f781aa817b3d13ace3411d (diff) |
Add optional support for types in QSettings::value
This add an optional named parameter to the function value()
to automatically cast the type that is being returned
by the function.
An example of this situation could be an ini file that contains
the value of a one-element list:
settings.setValue('var', ['a'])
The the ini file will be:
[General]
var=a # we cannot know that this is a list!
Once we read it, we could specify if we want
the default behavior, a str, or to cast the output
to a list.
settings.value('var') # Will get "a"
settings.value('var', type=list) # Will get ["a"]
The cppgenerator was modified to add a verification step
before trying to get the named parameter, since it could
be optional and having one named parameter was assumming
that all of them were provided.
Change-Id: I8f379debea86b42cf89019d432e990084c9e6614
Fixes: PYSIDE-1010
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Christian Tismer <tismer@stackless.com>
-rw-r--r-- | sources/pyside2/PySide2/QtCore/typesystem_core_common.xml | 11 | ||||
-rw-r--r-- | sources/pyside2/PySide2/glue/qtcore.cpp | 50 | ||||
-rw-r--r-- | sources/pyside2/tests/QtCore/CMakeLists.txt | 1 | ||||
-rw-r--r-- | sources/pyside2/tests/QtCore/qsettings_test.ini | 4 | ||||
-rw-r--r-- | sources/pyside2/tests/QtCore/qsettings_test.py | 77 | ||||
-rw-r--r-- | sources/shiboken2/generator/shiboken2/cppgenerator.cpp | 10 |
6 files changed, 145 insertions, 8 deletions
diff --git a/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml b/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml index 2173e747b..78a731458 100644 --- a/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml +++ b/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml @@ -2511,11 +2511,12 @@ <define-ownership class="target" owner="default"/> </modify-argument> </modify-function> - <modify-function signature="value(const QString&,const QVariant&)const"> - <inject-documentation mode="append" format="target"> - .. warning:: QSettings.value can return different types (QVariant types) depending on the platform it's running on, so the safest way to use it is always casting the result to the desired type, e.g.: int(settings.value("myKey")) - </inject-documentation> - </modify-function> + <!-- PYSIDE-1010: + We remove the original implementation of value() to include the optional parameter --> + <modify-function signature="value(const QString&,const QVariant&)const" remove="all"/> + <add-function signature="value(const QString&, const QVariant& @defaultValue@ = 0, PyObject* @type@ = 0)" return-type="PyObject*"> + <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qsettings-value"/> + </add-function> </object-type> <object-type name="QEvent" polymorphic-id-expression="%1->type() == QEvent::None"> <enum-type name="Type"/> diff --git a/sources/pyside2/PySide2/glue/qtcore.cpp b/sources/pyside2/PySide2/glue/qtcore.cpp index 930ad9349..3e1bab97b 100644 --- a/sources/pyside2/PySide2/glue/qtcore.cpp +++ b/sources/pyside2/PySide2/glue/qtcore.cpp @@ -56,6 +56,56 @@ bool py2kStrCheck(PyObject *obj) } // @snippet pystring-check +// @snippet qsettings-value +QVariant out = %CPPSELF.value(%1, %2); +PyTypeObject *typeObj = reinterpret_cast<PyTypeObject*>(%PYARG_3); + +if (typeObj) { + if (typeObj == &PyList_Type) { + QByteArrayList valuesList = out.toByteArray().split(','); + const int valuesSize = valuesList.size(); + if (valuesSize > 0) { + PyObject *list = PyList_New(valuesSize); + for (int i = 0; i < valuesSize; i++) { + PyObject *item = PyUnicode_FromString(valuesList[i].data()); + PyList_SET_ITEM(list, i, item); + Py_DECREF(item); + } + %PYARG_0 = list; + + } else { + %PYARG_0 = %CONVERTTOPYTHON[QVariant](out); + } + } else if (typeObj == &PyBytes_Type) { + QByteArray asByteArray = out.toByteArray(); + %PYARG_0 = PyBytes_FromString(asByteArray.data()); + } else if (typeObj == &PyUnicode_Type) { + QByteArray asByteArray = out.toByteArray(); + %PYARG_0 = PyUnicode_FromString(asByteArray.data()); +#ifdef IS_PY3K + } else if (typeObj == &PyLong_Type) { + float asFloat = out.toFloat(); + pyResult = PyLong_FromDouble(asFloat); +#else + } else if (typeObj == &PyInt_Type) { + float asFloat = out.toFloat(); + pyResult = PyInt_FromLong(long(asFloat)); +#endif + } else if (typeObj == &PyFloat_Type) { + float asFloat = out.toFloat(); + %PYARG_0 = PyFloat_FromDouble(asFloat); + } + // TODO: PyDict_Type and PyTuple_Type +} +else { + if (out == 0) + %PYARG_0 = Py_None; + else + %PYARG_0 = %CONVERTTOPYTHON[QVariant](out); +} + +// @snippet qsettings-value + // @snippet qvariant-conversion static const char *QVariant_resolveMetaType(PyTypeObject *type, int *typeId) { diff --git a/sources/pyside2/tests/QtCore/CMakeLists.txt b/sources/pyside2/tests/QtCore/CMakeLists.txt index 08e63d043..d05699f16 100644 --- a/sources/pyside2/tests/QtCore/CMakeLists.txt +++ b/sources/pyside2/tests/QtCore/CMakeLists.txt @@ -96,6 +96,7 @@ PYSIDE_TEST(qrect_test.py) PYSIDE_TEST(qregexp_test.py) PYSIDE_TEST(qregularexpression_test.py) PYSIDE_TEST(qresource_test.py) +PYSIDE_TEST(qsettings_test.py) PYSIDE_TEST(qsize_test.py) PYSIDE_TEST(qslot_object_test.py) PYSIDE_TEST(qsocketnotifier_test.py) diff --git a/sources/pyside2/tests/QtCore/qsettings_test.ini b/sources/pyside2/tests/QtCore/qsettings_test.ini new file mode 100644 index 000000000..f54ae0029 --- /dev/null +++ b/sources/pyside2/tests/QtCore/qsettings_test.ini @@ -0,0 +1,4 @@ +[General] +var1=a, b, c +var2=a + diff --git a/sources/pyside2/tests/QtCore/qsettings_test.py b/sources/pyside2/tests/QtCore/qsettings_test.py new file mode 100644 index 000000000..6d64b0db3 --- /dev/null +++ b/sources/pyside2/tests/QtCore/qsettings_test.py @@ -0,0 +1,77 @@ +############################################################################# +## +## Copyright (C) 2019 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of Qt for Python. +## +## $QT_BEGIN_LICENSE:GPL-EXCEPT$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and The Qt Company. For licensing terms +## and conditions see https://www.qt.io/terms-conditions. For further +## information use the contact form at https://www.qt.io/contact-us. +## +## GNU General Public License Usage +## Alternatively, this file may be used under the terms of the GNU +## General Public License version 3 as published by the Free Software +## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +## included in the packaging of this file. Please review the following +## information to ensure the GNU General Public License requirements will +## be met: https://www.gnu.org/licenses/gpl-3.0.html. +## +## $QT_END_LICENSE$ +## +############################################################################# + +'''Test cases for QDate''' + +import unittest + +import os +from helper import adjust_filename +import py3kcompat as py3k +from PySide2.QtCore import QSettings + +class TestQSettings(unittest.TestCase): + def testConversions(self): + file_path = adjust_filename('qsettings_test.ini', __file__) + settings = QSettings(file_path, QSettings.IniFormat) + + r = settings.value('var1') + self.assertEqual(type(r), list) + + r = settings.value('var2') + if py3k.IS_PY3K: + self.assertEqual(type(r), str) + else: + self.assertEqual(type(r), unicode) + + r = settings.value('var2', type=list) + self.assertEqual(type(r), list) + + + def testDefaultValueConversion(self): + settings = QSettings('foo.ini', QSettings.IniFormat) + r = settings.value('lala', 22) + if py3k.IS_PY3K: + self.assertEqual(type(r), int) + else: + self.assertEqual(type(r), long) + + r = settings.value('lala', 22, type=str) + self.assertEqual(type(r), str) + + r = settings.value('lala', 22, type=bytes) + self.assertEqual(type(r), bytes) + + r = settings.value('lala', 22, type=int) + self.assertEqual(type(r), int) + + r = settings.value('lala', 22, type=float) + self.assertEqual(type(r), float) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp index 84f0cd1f5..e36b6edc3 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp @@ -3032,18 +3032,21 @@ void CppGenerator::writeNamedArgumentResolution(QTextStream &s, const AbstractMe s << INDENT << "if (kwds) {" << endl; { Indentation indent(INDENT); - s << INDENT << "PyObject *"; + s << INDENT << "PyObject *keyName = nullptr;" << endl; + s << INDENT << "PyObject *value = nullptr;" << endl; for (const AbstractMetaArgument *arg : args) { int pyArgIndex = arg->argumentIndex() - OverloadData::numberOfRemovedArguments(func, arg->argumentIndex()); QString pyArgName = usePyArgs ? pythonArgsAt(pyArgIndex) : QLatin1String(PYTHON_ARG); - s << "value = PyDict_GetItemString(kwds, \"" << arg->name() << "\");" << endl; + s << INDENT << "keyName = Py_BuildValue(\"s\",\"" << arg->name() << "\");" << endl; + s << INDENT << "if (PyDict_Contains(kwds, keyName)) {" << endl; + s << INDENT << "value = PyDict_GetItemString(kwds, \"" << arg->name() << "\");" << endl; s << INDENT << "if (value && " << pyArgName << ") {" << endl; { Indentation indent(INDENT); s << INDENT << pyErrString.arg(arg->name()) << endl; s << INDENT << returnStatement(m_currentErrorCode) << endl; } - s << INDENT << "} else if (value) {" << endl; + s << INDENT << INDENT << "} else if (value) {" << endl; { Indentation indent(INDENT); s << INDENT << pyArgName << " = value;" << endl; @@ -3058,6 +3061,7 @@ void CppGenerator::writeNamedArgumentResolution(QTextStream &s, const AbstractMe s << INDENT << '}' << endl; if (arg != args.constLast()) s << INDENT; + s << "}" << endl; } } s << INDENT << '}' << endl; |