diff options
| -rw-r--r-- | sources/pyside6/doc/extras/QtCore.ClassInfo.rst | 17 | ||||
| -rw-r--r-- | sources/pyside6/libpyside/pysideclassinfo.cpp | 22 | ||||
| -rw-r--r-- | sources/pyside6/tests/QtCore/classinfo_test.py | 29 |
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__': |
