aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside6
diff options
context:
space:
mode:
authorBrett Stottlemyer <bstottle@ford.com>2021-07-03 15:46:02 -0400
committerBrett Stottlemyer <bstottle@ford.com>2021-07-29 04:17:54 -0400
commit71d8ac47106b82d8b507d5004c0dda8156c5eb91 (patch)
treee14b08db1b713feada0b7afef21059d350b22a23 /sources/pyside6
parent45a8fafb9c445ebcdea125b0c20cd14dc42784d1 (diff)
Allow spaces in ClassInfo keys
Qt Remote Objects uses ClassInfo keys with spaces. Because PySide uses keyword arguments for keys in the ClassInfo() decorator, it is not possible to create the QtRO info from PySide. This change supports both the current keyword processing as well as passing a python dict. Thus, for example, the following becomes possible: @ClassInfo({'RemoteObject Type': 'Simple', 'RemoteObject Signature':'c6f33edb0554ba4241aad1286a47c8189d65c845'}) class SimpleSource(QObject): ... Task-number: PYSIDE-862 Change-Id: I7764e92a46869766582611a70628dd23d033e09c Reviewed-by: Christian Tismer <tismer@stackless.com>
Diffstat (limited to 'sources/pyside6')
-rw-r--r--sources/pyside6/doc/extras/QtCore.ClassInfo.rst17
-rw-r--r--sources/pyside6/libpyside/pysideclassinfo.cpp22
-rw-r--r--sources/pyside6/tests/QtCore/classinfo_test.py29
3 files changed, 56 insertions, 12 deletions
diff --git a/sources/pyside6/doc/extras/QtCore.ClassInfo.rst b/sources/pyside6/doc/extras/QtCore.ClassInfo.rst
index b767ae153..0cb6d32ed 100644
--- a/sources/pyside6/doc/extras/QtCore.ClassInfo.rst
+++ b/sources/pyside6/doc/extras/QtCore.ClassInfo.rst
@@ -4,20 +4,33 @@
ClassInfo
*********
-This class is used to associates extra information to the class, which is available
+This class is used to associate extra information to the class, which is available
using QObject.metaObject(). Qt and PySide doesn't use this information.
The extra information takes the form of a dictionary with key and value in a literal string.
+The recommended usage is to provide the key/value using python keyword syntax, where the
+keyword becomes the key, and the provided string becomes the value.
+
+If the key needs to contain special characters (spaces, commas, '::', start with a number, etc),
+it is also possible to pass a python dictionary with arbitrary strings for both the key and
+value and enabling special characters in the key.
+
.. note:: This Class is a implementation of Q_CLASSINFO macro.
-
+
Example
-------
::
+ # Recommended syntax
@ClassInfo(Author='PySide Team', URL='http://www.pyside.org')
class MyObject(QObject):
...
+
+ # Provided to support keys not supported by Python's keyword syntax
+ @ClassInfo({'Some key text $': 'This syntax supports special characters in keys'})
+ class MyObject(QObject):
+ ...
diff --git a/sources/pyside6/libpyside/pysideclassinfo.cpp b/sources/pyside6/libpyside/pysideclassinfo.cpp
index 6bd5a7650..01f72968d 100644
--- a/sources/pyside6/libpyside/pysideclassinfo.cpp
+++ b/sources/pyside6/libpyside/pysideclassinfo.cpp
@@ -136,8 +136,19 @@ static PyObject *classInfoTpNew(PyTypeObject *subtype, PyObject * /* args */, Py
int classInfoTpInit(PyObject *self, PyObject *args, PyObject *kwds)
{
- if (PyTuple_Check(args) && PyTuple_Size(args) > 0) {
- PyErr_Format(PyExc_TypeError, "ClassInfo() takes exactly 0 positional arguments (%zd given)", PyTuple_Size(args));
+ PyObject *infoDict = nullptr;
+ auto size = PyTuple_Size(args);
+ if (size == 1 && !kwds) {
+ PyObject *tmp = PyTuple_GET_ITEM(args, 0);
+ if (PyDict_Check(tmp))
+ infoDict = tmp;
+ } else if (size == 0 && kwds && PyDict_Check(kwds)) {
+ infoDict = kwds;
+ }
+
+ if (!infoDict) {
+ PyErr_Format(PyExc_TypeError, "ClassInfo() takes either keyword argument(s) or "
+ "a single dictionary argument");
return -1;
}
@@ -149,12 +160,13 @@ int classInfoTpInit(PyObject *self, PyObject *args, PyObject *kwds)
Py_ssize_t pos = 0;
// PyDict_Next causes a segfault if kwds is empty
- if (kwds && PyDict_Check(kwds) && PyDict_Size(kwds) > 0) {
- while (PyDict_Next(kwds, &pos, &key, &value)) {
+ if (PyDict_Size(infoDict) > 0) {
+ while (PyDict_Next(infoDict, &pos, &key, &value)) {
if (Shiboken::String::check(key) && Shiboken::String::check(value)) {
pData->m_data[Shiboken::String::toCString(key)] = Shiboken::String::toCString(value);
} else {
- PyErr_SetString(PyExc_TypeError, "All keys and values provided to ClassInfo() must be strings");
+ PyErr_SetString(PyExc_TypeError, "All keys and values provided to ClassInfo() "
+ "must be strings");
return -1;
}
}
diff --git a/sources/pyside6/tests/QtCore/classinfo_test.py b/sources/pyside6/tests/QtCore/classinfo_test.py
index 7fed56bf7..697f9c8d8 100644
--- a/sources/pyside6/tests/QtCore/classinfo_test.py
+++ b/sources/pyside6/tests/QtCore/classinfo_test.py
@@ -57,6 +57,23 @@ class TestClassInfo(unittest.TestCase):
self.assertEqual(ci.name(), 'url')
self.assertEqual(ci.value(), 'http://www.pyside.org')
+ def test_dictionary(self):
+ @ClassInfo({'author':'pyside', 'author company':'The Qt Company'})
+ class MyObject(QObject):
+ pass
+
+ o = MyObject()
+ mo = o.metaObject()
+ self.assertEqual(mo.classInfoCount(), 2)
+
+ ci = mo.classInfo(0) # author
+ self.assertEqual(ci.name(), 'author')
+ self.assertEqual(ci.value(), 'pyside')
+
+ ci = mo.classInfo(1) # url
+ self.assertEqual(ci.name(), 'author company')
+ self.assertEqual(ci.value(), 'The Qt Company')
+
def test_verify_metadata_types(self):
valid_dict = { '123': '456' }
@@ -94,25 +111,27 @@ class TestClassInfo(unittest.TestCase):
self.assertRaises(TypeError, decorator, MyObject2)
def test_can_only_be_used_on_qobjects(self):
+ def make_info():
+ return ClassInfo(author='pyside')
def test_function():
pass
- self.assertRaises(TypeError, ClassInfo(), test_function)
+ self.assertRaises(TypeError, make_info(), test_function)
class NotAQObject(object):
pass
- self.assertRaises(TypeError, ClassInfo(), NotAQObject)
+ self.assertRaises(TypeError, make_info(), NotAQObject)
class QObjectSubclass(QObject):
pass
- ClassInfo()(QObjectSubclass)
+ make_info()(QObjectSubclass)
class SubclassOfNativeQObjectSubclass(QCoreApplication):
pass
- ClassInfo()(SubclassOfNativeQObjectSubclass)
+ make_info()(SubclassOfNativeQObjectSubclass)
class SubclassOfPythonQObjectSubclass(QObjectSubclass):
pass
- ClassInfo()(SubclassOfPythonQObjectSubclass)
+ make_info()(SubclassOfPythonQObjectSubclass)
if __name__ == '__main__':